Compare commits

..

8 commits

Author SHA1 Message Date
Conventional Changelog Action
81cfc2d704 chore(release): 🚀 v4.43.18 [skip ci] 2024-05-14 19:54:45 +00:00
TidusJar
5de350ce2c Merge branch 'net8' of https://github.com/ombi-app/ombi into net8 2024-05-14 20:52:23 +01:00
TidusJar
55635edc21 more .net8 2024-05-14 20:52:16 +01:00
Conventional Changelog Action
a3c40ad835 chore(release): 🚀 v4.43.17 [skip ci] 2024-05-14 19:50:41 +00:00
TidusJar
a83b781367 missed docker 2024-05-14 20:49:38 +01:00
TidusJar
4fd9925376 stuff 2024-05-14 20:47:53 +01:00
TidusJar
adb4e32696 packages 2024-05-14 20:34:47 +01:00
TidusJar
edff259e64 framework change 2024-05-14 20:27:11 +01:00
131 changed files with 5421 additions and 14162 deletions

View file

@ -24,7 +24,7 @@ jobs:
with:
node-version: '18'
- uses: actions/cache@v4
- uses: actions/cache@v2
with:
path: |
'**/node_modules'

View file

@ -15,7 +15,7 @@ jobs:
node-version: '18'
- name: NodeModules Cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
@ -27,7 +27,7 @@ jobs:
run: yarn --cwd ./src/Ombi/ClientApp run build
- name: Publish UI Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: angular_dist
path: |
@ -42,7 +42,7 @@ jobs:
dotnet-version: '8.0.x'
- name: Nuget Cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
@ -84,10 +84,10 @@ jobs:
strategy:
matrix:
include:
- os: win-x64
- os: win10-x64
format: zip
compression: zip
- os: win-x86
- os: win10-x86
format: zip
compression: zip
- os: linux-x64
@ -112,7 +112,7 @@ jobs:
dotnet-version: '5.0.x'
- name: Nuget Cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
@ -130,7 +130,7 @@ jobs:
working-directory: src/Ombi
- name: Download Angular
uses: actions/download-artifact@v4
uses: actions/download-artifact@v2
with:
name: angular_dist
path: ~/src/Ombi/dist
@ -156,7 +156,7 @@ jobs:
directory: 'src/Ombi/${{ matrix.os }}'
- name: Publish Release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.os }}
path: |
@ -170,7 +170,7 @@ jobs:
- name: Download Artifacts
id: download
uses: actions/download-artifact@v4
uses: actions/download-artifact@v2
with:
path: artifacts

View file

@ -17,7 +17,7 @@
# fetch-depth: 0
# - name: NodeModules Cache
# uses: actions/cache@v4
# uses: actions/cache@v2
# with:
# path: '**/node_modules'
# key: node_modules-${{ hashFiles('**/yarn.lock') }}

View file

@ -37,7 +37,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@ -48,7 +48,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -62,4 +62,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v1

View file

@ -20,7 +20,7 @@ jobs:
node-version: '18'
- name: NodeModules Cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
@ -41,7 +41,7 @@ jobs:
dotnet-version: '8.0.x'
- name: Nuget Cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
@ -76,10 +76,10 @@ jobs:
strategy:
matrix:
include:
- os: win-x64
- os: win10-x64
format: zip
compression: zip
- os: win-x86
- os: win10-x86
format: zip
compression: zip
- os: linux-x64
@ -101,7 +101,7 @@ jobs:
dotnet-version: '8.0.x'
- name: Nuget Cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}

View file

@ -1,226 +1,8 @@
## [4.49.3](https://github.com/Ombi-app/Ombi/compare/v4.49.2...v4.49.3) (2025-08-17)
## [4.43.18](https://github.com/Ombi-app/Ombi/compare/v4.43.17...v4.43.18) (2024-05-14)
### Bug Fixes
* **plex-api:** update Plex Watchlist URL ([11fd7a5](https://github.com/Ombi-app/Ombi/commit/11fd7a5fc853da75974a16bf4fdecd72a836f54b))
## [4.49.2](https://github.com/Ombi-app/Ombi/compare/v4.49.1...v4.49.2) (2025-07-12)
### Performance Improvements
* **discover:** :zap: Improve the loading performance on the discover page ([97d5167](https://github.com/Ombi-app/Ombi/commit/97d5167db6c9f915021f32b96b281d7db3741d7f))
## [4.49.1](https://github.com/Ombi-app/Ombi/compare/v4.49.0...v4.49.1) (2025-07-12)
### Bug Fixes
* **auth:** Fixed an issue where refreshing the page as a power user would stop the application from loading [#5242](https://github.com/Ombi-app/Ombi/issues/5242) ([cee4014](https://github.com/Ombi-app/Ombi/commit/cee40146ee02f7fb79e2019d6fe2f9d5c5dbdfc8))
# [4.49.0](https://github.com/Ombi-app/Ombi/compare/v4.48.5...v4.49.0) (2025-07-11)
### Features
* Added the ability for the Watchlist to automatically refresh the users token. This will reduce the need for the user to log in ([067c029](https://github.com/Ombi-app/Ombi/commit/067c029f42e9fd853d060fdb2093013b15ac14c0))
## [4.48.5](https://github.com/Ombi-app/Ombi/compare/v4.48.4...v4.48.5) (2025-05-14)
### Bug Fixes
* filter out excluded notification agents from user preferences ([c9ab4f4](https://github.com/Ombi-app/Ombi/commit/c9ab4f4f9faa66dbf263da693db1eefcf68beeec)), closes [#5196](https://github.com/Ombi-app/Ombi/issues/5196)
## [4.48.4](https://github.com/Ombi-app/Ombi/compare/v4.48.3...v4.48.4) (2025-05-14)
### Bug Fixes
* **translations:** 🌐 New translations from Crowdin [skip ci] ([dbbfdd9](https://github.com/Ombi-app/Ombi/commit/dbbfdd926f0808f6d16f0b2cd8b5406e6b610c82))
* **translations:** 🌐 New translations from Crowdin [skip ci] ([53a6a09](https://github.com/Ombi-app/Ombi/commit/53a6a092b14b8b8bdbff95d066926d3dbe6951f4))
* **ui:** correct timezone handling in OmbiDatePipe ([f88c5ad](https://github.com/Ombi-app/Ombi/commit/f88c5ad818fadea7064e7dfbe46f07eae855109a)), closes [#5102](https://github.com/Ombi-app/Ombi/issues/5102)
## [4.48.3](https://github.com/Ombi-app/Ombi/compare/v4.48.2...v4.48.3) (2025-05-14)
### Bug Fixes
* Correct 4K movie request existence check ([ba6e708](https://github.com/Ombi-app/Ombi/commit/ba6e708e189f52f2ff4ebc073fa38a4f53f1061c)), closes [#4798](https://github.com/Ombi-app/Ombi/issues/4798)
## [4.48.2](https://github.com/Ombi-app/Ombi/compare/v4.48.1...v4.48.2) (2025-05-14)
### Bug Fixes
* **radarr:** ensure RequestedUser is loaded when creating tags ([f8658fe](https://github.com/Ombi-app/Ombi/commit/f8658fe6d56488aa5caa68093245cbf021a31810)), closes [#5045](https://github.com/Ombi-app/Ombi/issues/5045)
## [4.48.1](https://github.com/Ombi-app/Ombi/compare/v4.48.0...v4.48.1) (2025-05-14)
# [4.48.0](https://github.com/Ombi-app/Ombi/compare/v4.47.3...v4.48.0) (2025-05-14)
### Features
* added the watchlist notification ([0dfd453](https://github.com/Ombi-app/Ombi/commit/0dfd4533dba01cb04ea2217c020de8833ddf39c6))
## [4.47.3](https://github.com/Ombi-app/Ombi/compare/v4.47.2...v4.47.3) (2025-04-13)
### Bug Fixes
* [#5223](https://github.com/Ombi-app/Ombi/issues/5223) ([cf0c161](https://github.com/Ombi-app/Ombi/commit/cf0c1614a496b4f7cf19d78e885c3e37dae5cf0f))
## [4.47.2](https://github.com/Ombi-app/Ombi/compare/v4.47.0...v4.47.2) (2025-03-11)
### Bug Fixes
* **user-import:** Do not import users that do not have access to the server [#5064](https://github.com/Ombi-app/Ombi/issues/5064) ([a801cfd](https://github.com/Ombi-app/Ombi/commit/a801cfdb0946cbee3c35b7e917a240f69020f221))
# [4.47.0](https://github.com/Ombi-app/Ombi/compare/v4.46.8...v4.47.0) (2025-01-03)
### Features
* **wizard:** :sparkles: Added the ability to start with a different database ([#5208](https://github.com/Ombi-app/Ombi/issues/5208)) ([cc98fc6](https://github.com/Ombi-app/Ombi/commit/cc98fc6aca27111a8afc3b7b5b8e53207b73fe15))
## [4.46.8](https://github.com/Ombi-app/Ombi/compare/v4.46.7...v4.46.8) (2025-01-03)
### Bug Fixes
* **radarr-settings:** this.normalForm is undefined ([#5207](https://github.com/Ombi-app/Ombi/issues/5207)) ([dc2b958](https://github.com/Ombi-app/Ombi/commit/dc2b958915bf6cb77e093ada843ef6d9f62a3755)), closes [#4994](https://github.com/Ombi-app/Ombi/issues/4994)
## [4.46.7](https://github.com/Ombi-app/Ombi/compare/v4.46.6...v4.46.7) (2024-12-03)
### Bug Fixes
* **requests:** :bug: Power users can now set profiles and root folders when requesting ([138df1e](https://github.com/Ombi-app/Ombi/commit/138df1eb25c709c1939d01d4c9f9ece63f8e0fde))
## [4.46.6](https://github.com/Ombi-app/Ombi/compare/v4.46.5...v4.46.6) (2024-11-24)
## [4.46.5](https://github.com/Ombi-app/Ombi/compare/v4.46.4...v4.46.5) (2024-11-23)
### Bug Fixes
* **Fixed the UI not applying the correct timezone settings:** :bug: ([029ea79](https://github.com/Ombi-app/Ombi/commit/029ea7919220fbc506898733caeb4370053051a7))
## [4.46.4](https://github.com/Ombi-app/Ombi/compare/v4.46.3...v4.46.4) (2024-09-09)
## [4.46.3](https://github.com/Ombi-app/Ombi/compare/v4.46.2...v4.46.3) (2024-09-07)
### Bug Fixes
* **radarr-4k:** :bug: Fixed an issue where the overrides wouldn't work for 4k Requests ([0fb29a0](https://github.com/Ombi-app/Ombi/commit/0fb29a0b16b1fc87f71df1a589f6141324cf2f1b))
## [4.46.2](https://github.com/Ombi-app/Ombi/compare/v4.46.1...v4.46.2) (2024-09-03)
### Bug Fixes
* **radarr:** :bug: Enable validation on the radarr settings page ([0af3511](https://github.com/Ombi-app/Ombi/commit/0af3511e819d24e0f4edf6f33931e61bba743224))
## [4.46.1](https://github.com/Ombi-app/Ombi/compare/v4.46.0...v4.46.1) (2024-08-27)
### Bug Fixes
* src/Ombi.Notifications/Ombi.Notifications.csproj to reduce vulnerabilities ([#5167](https://github.com/Ombi-app/Ombi/issues/5167)) ([e1f2a84](https://github.com/Ombi-app/Ombi/commit/e1f2a848065d79c8bba9eafff4f1f5db4a994b53))
# [4.46.0](https://github.com/Ombi-app/Ombi/compare/v4.45.1...v4.46.0) (2024-08-20)
### Bug Fixes
* **discover:** Improved rendering on the discover page ([ea00d6c](https://github.com/Ombi-app/Ombi/commit/ea00d6c12f4441da243287d0fbc706d66c0afd82))
* src/Ombi.Store/Ombi.Store.csproj to reduce vulnerabilities ([#5160](https://github.com/Ombi-app/Ombi/issues/5160)) ([9c21074](https://github.com/Ombi-app/Ombi/commit/9c2107418939ee92e50c59765481f30efac12eff))
### Features
* upgrade @ngx-translate/core from 14.0.0 to 15.0.0 ([#5158](https://github.com/Ombi-app/Ombi/issues/5158)) ([48d3dec](https://github.com/Ombi-app/Ombi/commit/48d3dec26d36002a9d613432fb7f9232d8801cba))
* upgrade @ngx-translate/http-loader from 7.0.0 to 8.0.0 ([#5159](https://github.com/Ombi-app/Ombi/issues/5159)) ([3bd98c1](https://github.com/Ombi-app/Ombi/commit/3bd98c1d711786bff66f1528dcdddcafe256abd2))
## [4.45.1](https://github.com/Ombi-app/Ombi/compare/v4.45.0...v4.45.1) (2024-08-20)
### Bug Fixes
* **plex:** Fixed some errors around the scanner that was causing the scan to fail ([d9787dc](https://github.com/Ombi-app/Ombi/commit/d9787dc32aace808d196f6f87456ef45de3d7bbf))
# [4.45.0](https://github.com/Ombi-app/Ombi/compare/v4.44.1...v4.45.0) (2024-08-07)
# [4.44.0](https://github.com/Ombi-app/Ombi/compare/v4.43.22...v4.44.0) (2024-07-11)
### Features
* Adding postgres support to ombi (beta) ([#5050](https://github.com/Ombi-app/Ombi/issues/5050)) ([f8c6102](https://github.com/Ombi-app/Ombi/commit/f8c61027bf53d657d7955a98b69d7ab90b66a75a))
## [4.43.22](https://github.com/Ombi-app/Ombi/compare/v4.43.21...v4.43.22) (2024-07-08)
## [4.43.21](https://github.com/Ombi-app/Ombi/compare/v4.43.20...v4.43.21) (2024-06-26)
## [4.43.20](https://github.com/Ombi-app/Ombi/compare/v4.43.16...v4.43.20) (2024-05-14)
## [4.43.17](https://github.com/Ombi-app/Ombi/compare/v4.43.16...v4.43.17) (2024-05-14)
### Bug Fixes
@ -311,7 +93,7 @@
## [4.43.6](https://github.com/Ombi-app/Ombi/compare/v4.43.5...v4.43.6) (2023-11-01)
## [4.43.6](https://github.com/Ombi-app/Ombi/compare/v4.43.4...v4.43.6) (2023-11-01)
### Bug Fixes
@ -1203,257 +985,15 @@
## [4.44.1](https://github.com/Ombi-app/Ombi/compare/v4.44.0...v4.44.1) (2024-07-22)
## [4.39.1](https://github.com/Ombi-app/Ombi/compare/v4.39.0...v4.39.1) (2023-05-18)
## [4.43.5](https://github.com/Ombi-app/Ombi/compare/v4.43.4...v4.43.5) (2023-08-24)
## [4.35.11](https://github.com/Ombi-app/Ombi/compare/v4.38.2...v4.35.11) (2023-05-17)
# [4.44.0](https://github.com/Ombi-app/Ombi/compare/v4.43.22...v4.44.0) (2024-07-11)
### Features
* Adding postgres support to ombi (beta) ([#5050](https://github.com/Ombi-app/Ombi/issues/5050)) ([f8c6102](https://github.com/Ombi-app/Ombi/commit/f8c61027bf53d657d7955a98b69d7ab90b66a75a))
## [4.43.22](https://github.com/Ombi-app/Ombi/compare/v4.43.21...v4.43.22) (2024-07-08)
## [4.43.21](https://github.com/Ombi-app/Ombi/compare/v4.43.20...v4.43.21) (2024-06-26)
## [4.43.20](https://github.com/Ombi-app/Ombi/compare/v4.43.16...v4.43.20) (2024-05-14)
### Bug Fixes
* upgrade multiple dependencies with Snyk ([#5104](https://github.com/Ombi-app/Ombi/issues/5104)) [skip ci] ([a1083f6](https://github.com/Ombi-app/Ombi/commit/a1083f67c73c968b9ff0a0feebe5a9aac6a7c7c9))
## [4.43.16](https://github.com/Ombi-app/Ombi/compare/v4.43.15...v4.43.16) (2024-04-01)
## [4.43.15](https://github.com/Ombi-app/Ombi/compare/v4.43.14...v4.43.15) (2024-03-30)
### Bug Fixes
* fixed emails not being able to load the template ([6b49d9b](https://github.com/Ombi-app/Ombi/commit/6b49d9bc7108a0b663ca05de19dbf4841c9c43c1))
## [4.43.14](https://github.com/Ombi-app/Ombi/compare/v4.43.13...v4.43.14) (2024-03-06)
### Performance Improvements
* ⚡ Improve render performance on the discover, movie and tv pages ([#5084](https://github.com/Ombi-app/Ombi/issues/5084)) ([71c86a8](https://github.com/Ombi-app/Ombi/commit/71c86a8db9e63bf0ab779f9a8b5d62a42c246392))
## [4.43.13](https://github.com/Ombi-app/Ombi/compare/v4.43.12...v4.43.13) (2024-03-05)
## [4.43.12](https://github.com/Ombi-app/Ombi/compare/v4.43.11...v4.43.12) (2024-03-05)
### Bug Fixes
* src/Ombi/ClientApp/package.json & src/Ombi/ClientApp/yarn.lock to reduce vulnerabilities ([#5040](https://github.com/Ombi-app/Ombi/issues/5040)) [skip ci] ([955a742](https://github.com/Ombi-app/Ombi/commit/955a742fae1d0a3983c59cf77eb1a2d222f18b48))
* src/Ombi/ClientApp/package.json & src/Ombi/ClientApp/yarn.lock to reduce vulnerabilities ([#5072](https://github.com/Ombi-app/Ombi/issues/5072)) [skip ci] ([af6a986](https://github.com/Ombi-app/Ombi/commit/af6a9867719deb7b651a6a78352a8ce0df7a0cf0))
* src/Ombi/Ombi.csproj to reduce vulnerabilities ([#5066](https://github.com/Ombi-app/Ombi/issues/5066)) [skip ci] ([71df058](https://github.com/Ombi-app/Ombi/commit/71df05886512b8589f193a5cda0166c694438fc0))
* upgrade @fortawesome/fontawesome-free from 6.4.2 to 6.5.0 ([#5053](https://github.com/Ombi-app/Ombi/issues/5053)) [skip ci] ([5017e38](https://github.com/Ombi-app/Ombi/commit/5017e38f87e32821adb744935fffcb2d76927e2c))
* upgrade @types/jquery from 3.5.27 to 3.5.28 ([#5049](https://github.com/Ombi-app/Ombi/issues/5049)) [skip ci] ([2c8fe80](https://github.com/Ombi-app/Ombi/commit/2c8fe8087aea227e7425e82392ad9ccb3f8261b4))
* upgrade moment from 2.29.4 to 2.30.1 ([#5075](https://github.com/Ombi-app/Ombi/issues/5075)) [skip ci] ([460fa39](https://github.com/Ombi-app/Ombi/commit/460fa39bb95c73bafcd65fcc394fecca04d3ac49))
* upgrade multiple dependencies with Snyk ([#5073](https://github.com/Ombi-app/Ombi/issues/5073)) [skip ci] ([a27b459](https://github.com/Ombi-app/Ombi/commit/a27b4592471c58fca9ad5193b979171fa7c5e66d))
## [4.43.11](https://github.com/Ombi-app/Ombi/compare/v4.43.10...v4.43.11) (2024-01-11)
### Bug Fixes
* **emby:** Add more logging on the PlaySync to check for Tv Shows without a valid TMDB ([08eb13b](https://github.com/Ombi-app/Ombi/commit/08eb13b788582d576a0e1befdb8e84ef7ff0d2f3))
## [4.43.10](https://github.com/Ombi-app/Ombi/compare/v4.43.9...v4.43.10) (2023-11-20)
### Bug Fixes
* **radarr-4k:** 🐛 Fixed an issue when using Radarr 4k with user set quality profiles. There are now user quality profiles for 4k profile [#5025](https://github.com/Ombi-app/Ombi/issues/5025) ([62b9a1f](https://github.com/Ombi-app/Ombi/commit/62b9a1f65fc4ee5f1eaf9dfabf37742a9007433e))
## [4.43.9](https://github.com/Ombi-app/Ombi/compare/v4.43.8...v4.43.9) (2023-11-18)
### Bug Fixes
* **sonarr:** 🐛 Correctly monitor episodes ([57e7830](https://github.com/Ombi-app/Ombi/commit/57e7830f8e54b65ce3c1f0b122cbcc517d1af926))
## [4.43.8](https://github.com/Ombi-app/Ombi/compare/v4.43.7...v4.43.8) (2023-11-09)
## [4.43.7](https://github.com/Ombi-app/Ombi/compare/v4.43.6...v4.43.7) (2023-11-09)
### Bug Fixes
* upgrade @microsoft/signalr from 6.0.22 to 6.0.23 ([#5032](https://github.com/Ombi-app/Ombi/issues/5032)) [skip ci] ([11edac9](https://github.com/Ombi-app/Ombi/commit/11edac961b0b828658be83a9c4e67079345d3b0b))
* upgrade @types/jquery from 3.5.22 to 3.5.23 ([#5034](https://github.com/Ombi-app/Ombi/issues/5034)) [skip ci] ([9e28879](https://github.com/Ombi-app/Ombi/commit/9e28879fc1a479e1bd77ca003e3e748fec27f081))
## [4.43.6](https://github.com/Ombi-app/Ombi/compare/v4.43.5...v4.43.6) (2023-11-01)
### Bug Fixes
* **discord:** 🐛 Fixed an issue where the Icon in the discord notifications wouldn't apply ([32da949](https://github.com/Ombi-app/Ombi/commit/32da949a9547f68c57eb4338f749228b7de167c2))
* src/Ombi/ClientApp/package.json & src/Ombi/ClientApp/yarn.lock to reduce vulnerabilities ([#5010](https://github.com/Ombi-app/Ombi/issues/5010)) [skip ci] ([9c2e1b4](https://github.com/Ombi-app/Ombi/commit/9c2e1b435305d51cc9ab7f5d6932ccd3fa723e6c))
* upgrade @fortawesome/fontawesome-free from 6.4.0 to 6.4.2 ([#5005](https://github.com/Ombi-app/Ombi/issues/5005)) [skip ci] ([f703ff2](https://github.com/Ombi-app/Ombi/commit/f703ff255cf389a60bdece824214d38f57f03f90))
* upgrade @microsoft/signalr from 6.0.18 to 6.0.20 ([#4999](https://github.com/Ombi-app/Ombi/issues/4999)) [skip ci] ([563a044](https://github.com/Ombi-app/Ombi/commit/563a0443ea09ff71c5aa740173b4f3c5627cb543))
* upgrade @microsoft/signalr from 6.0.21 to 6.0.22 ([#5020](https://github.com/Ombi-app/Ombi/issues/5020)) ([1261a44](https://github.com/Ombi-app/Ombi/commit/1261a446e7ffa4d7540623f76ecc9d7e643ca4ce))
* upgrade @types/jquery from 3.5.16 to 3.5.17 ([#5011](https://github.com/Ombi-app/Ombi/issues/5011)) [skip ci] ([40ee175](https://github.com/Ombi-app/Ombi/commit/40ee175ccd6e53b1254833163954b6a1be0d5251))
* upgrade @types/jquery from 3.5.18 to 3.5.19 ([#5022](https://github.com/Ombi-app/Ombi/issues/5022)) ([291425e](https://github.com/Ombi-app/Ombi/commit/291425e6091d90ac07010ff65cc3a53309965546))
* upgrade cypress-real-events from 1.10.0 to 1.10.1 ([#5014](https://github.com/Ombi-app/Ombi/issues/5014)) ([ed06c22](https://github.com/Ombi-app/Ombi/commit/ed06c22fb26fb605b857f3f8e1b26b2dbab15710))
* upgrade cypress-real-events from 1.8.1 to 1.9.1 ([#5000](https://github.com/Ombi-app/Ombi/issues/5000)) [skip ci] ([19e0a88](https://github.com/Ombi-app/Ombi/commit/19e0a886ced344bfe6284f3916fba12826b7de08))
* upgrade jquery from 3.7.0 to 3.7.1 ([#5015](https://github.com/Ombi-app/Ombi/issues/5015)) ([7bc915c](https://github.com/Ombi-app/Ombi/commit/7bc915cc14ed27ad0f35142279f9362e5b7b27b8))
* upgrade multiple dependencies with Snyk ([#5030](https://github.com/Ombi-app/Ombi/issues/5030)) ([7e1e254](https://github.com/Ombi-app/Ombi/commit/7e1e254cfe6c84c1f143388f436d63efd4686e55))
* upgrade zone.js from 0.13.1 to 0.13.2 ([#5019](https://github.com/Ombi-app/Ombi/issues/5019)) ([c5c8dda](https://github.com/Ombi-app/Ombi/commit/c5c8dda7e4f744fa47841efba9f0e8fee9ef67c6))
## [4.43.4](https://github.com/Ombi-app/Ombi/compare/v4.43.3...v4.43.4) (2023-07-28)
### Bug Fixes
* **user-importer:** Fixed not importing all correct users [#4989](https://github.com/Ombi-app/Ombi/issues/4989) ([34c32f8](https://github.com/Ombi-app/Ombi/commit/34c32f8338705ea3f790d95b91c9ada21a41b9f2))
## [4.43.3](https://github.com/Ombi-app/Ombi/compare/v4.43.2...v4.43.3) (2023-07-28)
### Bug Fixes
* switch back to the old plex friends API [#4989](https://github.com/Ombi-app/Ombi/issues/4989) ([c8ad12e](https://github.com/Ombi-app/Ombi/commit/c8ad12eb5f53889609d1793ae907afd33ba6ef38))
## [4.43.2](https://github.com/Ombi-app/Ombi/compare/v4.43.1...v4.43.2) (2023-07-19)
### Bug Fixes
* **plex-api:** Switch over to the new API to avoid deprecation & save… ([#4986](https://github.com/Ombi-app/Ombi/issues/4986)) ([2f2d35e](https://github.com/Ombi-app/Ombi/commit/2f2d35ec867a8e5488e368db294bd37bcf92d843))
* Remove old trending source ([#4987](https://github.com/Ombi-app/Ombi/issues/4987)) ([aacaa3e](https://github.com/Ombi-app/Ombi/commit/aacaa3e140b43f5d196da612f785cc4451717752))
## [4.43.1](https://github.com/Ombi-app/Ombi/compare/v4.43.0...v4.43.1) (2023-07-16)
### Bug Fixes
* **user-importer:** don't delete admins in the cleanup ([895b9bf](https://github.com/Ombi-app/Ombi/commit/895b9bf6a060a678d4b0cca8083aa96c38e47b95))
# [4.43.0](https://github.com/Ombi-app/Ombi/compare/v4.42.3...v4.43.0) (2023-07-14)
### Features
* Add Auto Approve 4K role ([#4982](https://github.com/Ombi-app/Ombi/issues/4982)) ([#4983](https://github.com/Ombi-app/Ombi/issues/4983)) ([ac05495](https://github.com/Ombi-app/Ombi/commit/ac054954254b9d77a42e057f1065570c7fdc1093)), closes [#4957](https://github.com/Ombi-app/Ombi/issues/4957)
## [4.42.3](https://github.com/Ombi-app/Ombi/compare/v4.42.2...v4.42.3) (2023-07-13)
### Bug Fixes
* **user-importer:** Do not delete the Plex Admin as part of the user Importer cleanup [#4870](https://github.com/Ombi-app/Ombi/issues/4870) ([#4981](https://github.com/Ombi-app/Ombi/issues/4981)) ([4e80e7b](https://github.com/Ombi-app/Ombi/commit/4e80e7b7c3239a46a645ab6d1054993734ad4dd6))
## [4.42.2](https://github.com/Ombi-app/Ombi/compare/v4.42.1...v4.42.2) (2023-07-03)
### Bug Fixes
* Remove Angular TSLint ([#4973](https://github.com/Ombi-app/Ombi/issues/4973)) ([93969b5](https://github.com/Ombi-app/Ombi/commit/93969b5a2d82f442299bee418fae43cb590d7743))
* upgrade jquery from 3.6.1 to 3.7.0 ([#4974](https://github.com/Ombi-app/Ombi/issues/4974)) ([f2552ef](https://github.com/Ombi-app/Ombi/commit/f2552ef6ede011080a8d5499e11930c4d41d04c2))
* upgrade multiple dependencies with Snyk ([#4961](https://github.com/Ombi-app/Ombi/issues/4961)) ([3c3edf6](https://github.com/Ombi-app/Ombi/commit/3c3edf6273fa98c420989ebcebfee52b2545e402))
* upgrade zone.js from 0.11.8 to 0.13.0 ([#4975](https://github.com/Ombi-app/Ombi/issues/4975)) ([37f6564](https://github.com/Ombi-app/Ombi/commit/37f65648a2f8742020b0954acec4168aee048942))
## [4.42.1](https://github.com/Ombi-app/Ombi/compare/v4.42.0...v4.42.1) (2023-06-20)
### Bug Fixes
* More automation tests mainly around the Plex Settings page ([#4821](https://github.com/Ombi-app/Ombi/issues/4821)) ([21bfc5a](https://github.com/Ombi-app/Ombi/commit/21bfc5a45adf6da6a80854e19494a8ffdc9c0761))
* src/Ombi.Notifications/Ombi.Notifications.csproj to reduce vulnerabilities ([#4969](https://github.com/Ombi-app/Ombi/issues/4969)) [skip ci] ([8584ad4](https://github.com/Ombi-app/Ombi/commit/8584ad46053c51f5da40b24f3efd1b9e5a031ddd))
* upgrade @fortawesome/fontawesome-free from 6.1.2 to 6.4.0 ([#4965](https://github.com/Ombi-app/Ombi/issues/4965)) [skip ci] ([84454e5](https://github.com/Ombi-app/Ombi/commit/84454e53c00c808e8a393c7750bdc418a7593e91))
* upgrade @microsoft/signalr from 6.0.11 to 6.0.16 ([#4964](https://github.com/Ombi-app/Ombi/issues/4964)) [skip ci] ([a0201e3](https://github.com/Ombi-app/Ombi/commit/a0201e3f585dc52f717e33c46ede35a4eccac736))
* upgrade cypress-real-events from 1.7.4 to 1.8.1 ([#4968](https://github.com/Ombi-app/Ombi/issues/4968)) [skip ci] ([8a24b56](https://github.com/Ombi-app/Ombi/commit/8a24b56299c3bc98bf0d719ba448972aaa7f7461))
* upgrade multiple dependencies with Snyk ([#4963](https://github.com/Ombi-app/Ombi/issues/4963)) [skip ci] ([6025c5e](https://github.com/Ombi-app/Ombi/commit/6025c5ed757438d3a5d79bd36fd789ef0297ce70))
* upgrade primeng from 15.0.0-rc.1 to 15.4.1 ([#4962](https://github.com/Ombi-app/Ombi/issues/4962)) [skip ci] ([23a4fed](https://github.com/Ombi-app/Ombi/commit/23a4fede69898a25b342aed78a8cda553c1fd18d))
# [4.42.0](https://github.com/Ombi-app/Ombi/compare/v4.41.1...v4.42.0) (2023-06-02)
### Bug Fixes
* **translations:** 🌐 New translations from Crowdin [skip ci] ([#4926](https://github.com/Ombi-app/Ombi/issues/4926)) ([151efe1](https://github.com/Ombi-app/Ombi/commit/151efe19d0012b85f317c175da5ab4802ea14e20))
### Features
* **emby:** Show watched status for TV requests ([1f37de0](https://github.com/Ombi-app/Ombi/commit/1f37de08888812b6d130d92bb664a89e89149105))
## [4.41.1](https://github.com/Ombi-app/Ombi/compare/v4.41.0...v4.41.1) (2023-05-27)
# [4.41.0](https://github.com/Ombi-app/Ombi/compare/v4.40.0...v4.41.0) (2023-05-27)
### Bug Fixes
* Fix various styling issues ([#4935](https://github.com/Ombi-app/Ombi/issues/4935)) ([90b934a](https://github.com/Ombi-app/Ombi/commit/90b934a36996c0f489096f3641350a1c0d3b7c89))
### Features
* **emby:** Show end-user external IP address to Emby when logging in as an Emby user ([#4949](https://github.com/Ombi-app/Ombi/issues/4949)) ([79cef7e](https://github.com/Ombi-app/Ombi/commit/79cef7e0f8643e36536a9ea84dd1a07c232403a9)), closes [#4947](https://github.com/Ombi-app/Ombi/issues/4947)
# [4.40.0](https://github.com/Ombi-app/Ombi/compare/v4.39.1...v4.40.0) (2023-05-18)
## [4.35.10](https://github.com/Ombi-app/Ombi/compare/v4.35.9...v4.35.10) (2023-02-25)
@ -2211,3 +1751,123 @@
## [4.35.11](https://github.com/Ombi-app/Ombi/compare/v4.38.2...v4.35.11) (2023-05-17)
## [4.35.10](https://github.com/Ombi-app/Ombi/compare/v4.35.9...v4.35.10) (2023-02-25)
## [4.38.2](https://github.com/Ombi-app/Ombi/compare/v4.38.1...v4.38.2) (2023-05-17)
## [4.38.1](https://github.com/Ombi-app/Ombi/compare/v4.38.0...v4.38.1) (2023-05-09)
### Bug Fixes
* **API:** Allow RequestOnBehalf rights if requested from the API ([#4919](https://github.com/Ombi-app/Ombi/issues/4919)) ([bb6dedd](https://github.com/Ombi-app/Ombi/commit/bb6deddfaecb3d6c7c3c6970414444b619bb9106))
* **notificaitons:** Add the RequestedByAlias field to the Notification Message ([7e9c8be](https://github.com/Ombi-app/Ombi/commit/7e9c8bec6b02bb4e11f8db50394e493d4dd07723))
# [4.38.0](https://github.com/Ombi-app/Ombi/compare/v4.37.3...v4.38.0) (2023-05-07)
### Bug Fixes
* remove sort header ([969bc7b](https://github.com/Ombi-app/Ombi/commit/969bc7bb25ea900ab9199509b079b36843e5bd6f))
### Features
* **emby:** Show watched status for Movie requests ([9cfb10b](https://github.com/Ombi-app/Ombi/commit/9cfb10bb1ee69067a6f47bd2c8a72d4e6834350e))
## [4.37.3](https://github.com/Ombi-app/Ombi/compare/v4.37.2...v4.37.3) (2023-05-07)
### Bug Fixes
* Show the ApiAlias in the requests-list ([9ff624c](https://github.com/Ombi-app/Ombi/commit/9ff624ce4646815b239fbb8327117947f0a90e4b))
## [4.37.2](https://github.com/Ombi-app/Ombi/compare/v4.37.1...v4.37.2) (2023-05-03)
### Bug Fixes
* **jellyfin:** Fixed an issue where the sync could stop working. Removed unused properties so the deseralization no longer fails ([0e5e0ad](https://github.com/Ombi-app/Ombi/commit/0e5e0adf862701d0f672beff14ec0aa75e4b5220))
## [4.37.1](https://github.com/Ombi-app/Ombi/compare/v4.37.0...v4.37.1) (2023-05-02)
### Bug Fixes
* Cron Validation ([#4842](https://github.com/Ombi-app/Ombi/issues/4842)) ([97cc42f](https://github.com/Ombi-app/Ombi/commit/97cc42ffa8672e7d0d0996b5fbda7f7fe699da2d))
* **discover:** :children_crossing: Improved the new Genre buttons, it now includes TV results ([b087d60](https://github.com/Ombi-app/Ombi/commit/b087d606ff36565208e564f8856903f2a4098db5))
* **lidarr:** Change monitor to Existing to properly add artist [#3597](https://github.com/Ombi-app/Ombi/issues/3597) ([506f607](https://github.com/Ombi-app/Ombi/commit/506f60773bf1031d0be51ccd34289b855a04ea40)), closes [/github.com/Lidarr/Lidarr/issues/3597#issuecomment-1530804055](https://github.com//github.com/Lidarr/Lidarr/issues/3597/issues/issuecomment-1530804055)
# [4.37.0](https://github.com/Ombi-app/Ombi/compare/v4.36.1...v4.37.0) (2023-04-24)
### Features
* Search by genre ([1837419](https://github.com/Ombi-app/Ombi/commit/18374198f9f2462ba85c5781b0fcc05892728b21))
## [4.36.1](https://github.com/Ombi-app/Ombi/compare/v4.36.0...v4.36.1) (2023-04-20)
### Bug Fixes
* **healthchecks:** Removed redundant ping check ([1751305](https://github.com/Ombi-app/Ombi/commit/1751305064176d2c0135f867773ccc46b03915ec))
# [4.36.0](https://github.com/Ombi-app/Ombi/compare/v4.35.19...v4.36.0) (2023-04-20)
### Features
* **discover:** Add deny option to recently requested ([#4907](https://github.com/Ombi-app/Ombi/issues/4907)) ([78f340e](https://github.com/Ombi-app/Ombi/commit/78f340ee5f309c55690497170897533801957668))
## [4.35.19](https://github.com/Ombi-app/Ombi/compare/v4.35.18...v4.35.19) (2023-04-20)
### Bug Fixes
* **radarr:** Fixed an issue where the radarr sync would break ([de4baad](https://github.com/Ombi-app/Ombi/commit/de4baade9f87248d77106ff1a313a498870f4fb3))
## [4.35.18](https://github.com/Ombi-app/Ombi/compare/v4.35.17...v4.35.18) (2023-04-15)
### Bug Fixes
* **#4906:** :bug: Fixed an issue with power users and permissions ([80884bc](https://github.com/Ombi-app/Ombi/commit/80884bcd725c329867c278ad235cd4096cd4fe7a))
## [4.35.17](https://github.com/Ombi-app/Ombi/compare/v4.35.16...v4.35.17) (2023-04-15)
### Bug Fixes
* **discover:** Fix denied requests displayed as approved ([#4901](https://github.com/Ombi-app/Ombi/issues/4901)) ([1e87f20](https://github.com/Ombi-app/Ombi/commit/1e87f2010491b0f3fdda70d2b19d9afd94438df7))
* Fix denied movie shown as 'processing request' in details view ([#4900](https://github.com/Ombi-app/Ombi/issues/4900)) ([0069bfd](https://github.com/Ombi-app/Ombi/commit/0069bfdf54e0785bad45c832ca052f19fd4b940b))

161
README.md
View file

@ -122,10 +122,10 @@ Here are some of the features Ombi has:
</a>
</td>
<td align="center">
<a href="https://github.com/AmyJeanes">
<img src="https://avatars.githubusercontent.com/u/2363642?v=4" width="50;" alt="AmyJeanes"/>
<a href="https://github.com/MattJeanes">
<img src="https://avatars.githubusercontent.com/u/2363642?v=4" width="50;" alt="MattJeanes"/>
<br />
<sub><b>Amy Jeanes</b></sub>
<sub><b>Matt Jeanes</b></sub>
</a>
</td>
<td align="center">
@ -301,8 +301,8 @@ Here are some of the features Ombi has:
</a>
</td>
<td align="center">
<a href="https://github.com/tuxmi">
<img src="https://avatars.githubusercontent.com/u/12274612?v=4" width="50;" alt="tuxmi"/>
<a href="https://github.com/deepwather">
<img src="https://avatars.githubusercontent.com/u/12274612?v=4" width="50;" alt="deepwather"/>
<br />
<sub><b>Michael Reber</b></sub>
</a>
@ -407,14 +407,21 @@ Here are some of the features Ombi has:
<sub><b>Andrew Metzger</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Torkiliuz">
<img src="https://avatars.githubusercontent.com/u/460764?v=4" width="50;" alt="Torkiliuz"/>
<br />
<sub><b>Torkil</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/tombomb">
<img src="https://avatars.githubusercontent.com/u/544509?v=4" width="50;" alt="tombomb"/>
<br />
<sub><b>Tom McClellan</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/Tim-Trott">
<img src="https://avatars.githubusercontent.com/u/8249434?v=4" width="50;" alt="Tim-Trott"/>
@ -449,15 +456,15 @@ Here are some of the features Ombi has:
<br />
<sub><b>Sean Callinan</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/sambartik">
<img src="https://avatars.githubusercontent.com/u/63553146?v=4" width="50;" alt="sambartik"/>
<br />
<sub><b>Samuel Bartík</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/rob1998">
<img src="https://avatars.githubusercontent.com/u/1560707?v=4" width="50;" alt="rob1998"/>
@ -492,15 +499,15 @@ Here are some of the features Ombi has:
<br />
<sub><b>Micky</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/LMaxence">
<img src="https://avatars.githubusercontent.com/u/29194680?v=4" width="50;" alt="LMaxence"/>
<br />
<sub><b>Maxence Lecanu</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/mattmattmatt">
<img src="https://avatars.githubusercontent.com/u/927830?v=4" width="50;" alt="mattmattmatt"/>
@ -515,20 +522,6 @@ Here are some of the features Ombi has:
<sub><b>Marley</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/devbymadde">
<img src="https://avatars.githubusercontent.com/u/6094593?v=4" width="50;" alt="devbymadde"/>
<br />
<sub><b>Madeleine Schönemann</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Lucane">
<img src="https://avatars.githubusercontent.com/u/7999446?v=4" width="50;" alt="Lucane"/>
<br />
<sub><b>Lucane</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/zobe123">
<img src="https://avatars.githubusercontent.com/u/13840542?v=4" width="50;" alt="zobe123"/>
@ -542,15 +535,15 @@ Here are some of the features Ombi has:
<br />
<sub><b>Mike</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/tdorsey">
<img src="https://avatars.githubusercontent.com/u/1218404?v=4" width="50;" alt="tdorsey"/>
<br />
<sub><b>Tdorsey</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/sir-marv">
<img src="https://avatars.githubusercontent.com/u/3598205?v=4" width="50;" alt="sir-marv"/>
@ -585,15 +578,15 @@ Here are some of the features Ombi has:
<br />
<sub><b>Maartenheebink</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/m4tta">
<img src="https://avatars.githubusercontent.com/u/427218?v=4" width="50;" alt="m4tta"/>
<br />
<sub><b>M4tta</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/echel0n">
<img src="https://avatars.githubusercontent.com/u/1128022?v=4" width="50;" alt="echel0n"/>
@ -628,15 +621,15 @@ Here are some of the features Ombi has:
<br />
<sub><b>Blake Drumm</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/bazhip">
<img src="https://avatars.githubusercontent.com/u/10350445?v=4" width="50;" alt="bazhip"/>
<br />
<sub><b>Tim OBrien</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/Xirg">
<img src="https://avatars.githubusercontent.com/u/6020502?v=4" width="50;" alt="Xirg"/>
@ -652,17 +645,17 @@ Here are some of the features Ombi has:
</a>
</td>
<td align="center">
<a href="https://github.com/Torkiliuz">
<img src="https://avatars.githubusercontent.com/u/460764?v=4" width="50;" alt="Torkiliuz"/>
<a href="https://github.com/devbymadde">
<img src="https://avatars.githubusercontent.com/u/6094593?v=4" width="50;" alt="devbymadde"/>
<br />
<sub><b>Torkil</b></sub>
<sub><b>Madeleine Schönemann</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/sussycatgirl">
<img src="https://avatars.githubusercontent.com/u/26145882?v=4" width="50;" alt="sussycatgirl"/>
<a href="https://github.com/elisspace">
<img src="https://avatars.githubusercontent.com/u/18365129?v=4" width="50;" alt="elisspace"/>
<br />
<sub><b>Lea</b></sub>
<sub><b>Eli</b></sub>
</a>
</td>
<td align="center">
@ -671,15 +664,15 @@ Here are some of the features Ombi has:
<br />
<sub><b>Devin Buhl</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/davidtorosyan">
<img src="https://avatars.githubusercontent.com/u/46736285?v=4" width="50;" alt="davidtorosyan"/>
<br />
<sub><b>David Torosyan</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/hmnd">
<img src="https://avatars.githubusercontent.com/u/12853597?v=4" width="50;" alt="hmnd"/>
@ -687,13 +680,6 @@ Here are some of the features Ombi has:
<sub><b>David</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/dben">
<img src="https://avatars.githubusercontent.com/u/1358399?v=4" width="50;" alt="dben"/>
<br />
<sub><b>David Benson</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/danopia">
<img src="https://avatars.githubusercontent.com/u/40628?v=4" width="50;" alt="danopia"/>
@ -714,8 +700,7 @@ Here are some of the features Ombi has:
<br />
<sub><b>Christopher Demicoli</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/origamirobot">
<img src="https://avatars.githubusercontent.com/u/1346803?v=4" width="50;" alt="origamirobot"/>
@ -729,7 +714,8 @@ Here are some of the features Ombi has:
<br />
<sub><b>Calvin</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/Majawat">
<img src="https://avatars.githubusercontent.com/u/12058855?v=4" width="50;" alt="Majawat"/>
@ -752,19 +738,11 @@ Here are some of the features Ombi has:
</a>
</td>
<td align="center">
<a href="https://github.com/alasano">
<img src="https://avatars.githubusercontent.com/u/14372930?v=4" width="50;" alt="alasano"/>
<a href="https://github.com/Alasano">
<img src="https://avatars.githubusercontent.com/u/14372930?v=4" width="50;" alt="Alasano"/>
<br />
<sub><b>Aljosa Asanovic</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/AlexandrePicavet">
<img src="https://avatars.githubusercontent.com/u/25816980?v=4" width="50;" alt="AlexandrePicavet"/>
<br />
<sub><b>Alexandre Picavet</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/XanderStrike">
@ -779,7 +757,8 @@ Here are some of the features Ombi has:
<br />
<sub><b>Alexander Russell</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/AbeKline">
<img src="https://avatars.githubusercontent.com/u/8125653?v=4" width="50;" alt="AbeKline"/>
@ -787,6 +766,20 @@ Here are some of the features Ombi has:
<sub><b>Abe Kline</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Lucane">
<img src="https://avatars.githubusercontent.com/u/7999446?v=4" width="50;" alt="Lucane"/>
<br />
<sub><b>Lucane</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/sussycatgirl">
<img src="https://avatars.githubusercontent.com/u/26145882?v=4" width="50;" alt="sussycatgirl"/>
<br />
<sub><b>Lea</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/kmlucy">
<img src="https://avatars.githubusercontent.com/u/13952475?v=4" width="50;" alt="kmlucy"/>
@ -800,15 +793,15 @@ Here are some of the features Ombi has:
<br />
<sub><b>Kris Klosterman</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/jonocairns">
<img src="https://avatars.githubusercontent.com/u/182836?v=4" width="50;" alt="jonocairns"/>
<br />
<sub><b>Jono Cairns</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/jonbloom">
<img src="https://avatars.githubusercontent.com/u/492819?v=4" width="50;" alt="jonbloom"/>
@ -816,13 +809,6 @@ Here are some of the features Ombi has:
<sub><b>Jon Bloom</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/ExtremeFiretop">
<img src="https://avatars.githubusercontent.com/u/1971404?v=4" width="50;" alt="ExtremeFiretop"/>
<br />
<sub><b>Joel Samson</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/errorhandler">
<img src="https://avatars.githubusercontent.com/u/17112958?v=4" width="50;" alt="errorhandler"/>
@ -843,8 +829,7 @@ Here are some of the features Ombi has:
<br />
<sub><b>James White</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/JPyke3">
<img src="https://avatars.githubusercontent.com/u/13283054?v=4" width="50;" alt="JPyke3"/>
@ -858,7 +843,8 @@ Here are some of the features Ombi has:
<br />
<sub><b>Imgbot</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/comigor">
<img src="https://avatars.githubusercontent.com/u/735858?v=4" width="50;" alt="comigor"/>
@ -886,28 +872,13 @@ Here are some of the features Ombi has:
<br />
<sub><b>Grygon</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/Fish2">
<img src="https://avatars.githubusercontent.com/u/2311734?v=4" width="50;" alt="Fish2"/>
<br />
<sub><b>Fish2</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/elisspace">
<img src="https://avatars.githubusercontent.com/u/18365129?v=4" width="50;" alt="elisspace"/>
<br />
<sub><b>Eli</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Drewster727">
<img src="https://avatars.githubusercontent.com/u/4528753?v=4" width="50;" alt="Drewster727"/>
<br />
<sub><b>Drew</b></sub>
</a>
</td></tr>
</table>
<!-- readme: collaborators,contributors -end -->

2309
src/.idea/.idea.Ombi/.idea/contentModel.xml generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,440 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DBNavigator.Project.DDLFileAttachmentManager">
<mappings />
<preferences />
</component>
<component name="DBNavigator.Project.DatabaseAssistantManager">
<assistants />
</component>
<component name="DBNavigator.Project.DatabaseBrowserManager">
<autoscroll-to-editor value="false" />
<autoscroll-from-editor value="true" />
<show-object-properties value="true" />
<loaded-nodes />
</component>
<component name="DBNavigator.Project.DatabaseFileManager">
<open-files />
</component>
<component name="DBNavigator.Project.ExecutionManager">
<retain-sticky-names value="false" />
</component>
<component name="DBNavigator.Project.ParserDiagnosticsManager">
<diagnostics-history />
</component>
<component name="DBNavigator.Project.Settings">
<connections />
<browser-settings>
<general>
<display-mode value="TABBED" />
<navigation-history-size value="100" />
<show-object-details value="false" />
<enable-sticky-paths value="true" />
</general>
<filters>
<object-type-filter>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="true" />
<object-type name="ROLE" enabled="true" />
<object-type name="PRIVILEGE" enabled="true" />
<object-type name="CHARSET" enabled="true" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="MATERIALIZED_VIEW" enabled="true" />
<object-type name="NESTED_TABLE" enabled="true" />
<object-type name="COLUMN" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET_TRIGGER" enabled="true" />
<object-type name="DATABASE_TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="true" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
<object-type name="ARGUMENT" enabled="true" />
<object-type name="JAVA_CLASS" enabled="true" />
<object-type name="JAVA_INNER_CLASS" enabled="true" />
<object-type name="JAVA_FIELD" enabled="true" />
<object-type name="JAVA_METHOD" enabled="true" />
<object-type name="DIMENSION" enabled="true" />
<object-type name="CLUSTER" enabled="true" />
<object-type name="DBLINK" enabled="true" />
<object-type name="CREDENTIAL" enabled="true" />
<object-type name="AI_PROFILE" enabled="true" />
</object-type-filter>
</filters>
<sorting>
<object-type name="COLUMN" sorting-type="NAME" />
<object-type name="FUNCTION" sorting-type="NAME" />
<object-type name="PROCEDURE" sorting-type="NAME" />
<object-type name="ARGUMENT" sorting-type="POSITION" />
<object-type name="TYPE ATTRIBUTE" sorting-type="POSITION" />
</sorting>
<default-editors>
<object-type name="VIEW" editor-type="SELECTION" />
<object-type name="PACKAGE" editor-type="SELECTION" />
<object-type name="TYPE" editor-type="SELECTION" />
</default-editors>
</browser-settings>
<navigation-settings>
<lookup-filters>
<lookup-objects>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="false" />
<object-type name="ROLE" enabled="false" />
<object-type name="PRIVILEGE" enabled="false" />
<object-type name="CHARSET" enabled="false" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="MATERIALIZED VIEW" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET TRIGGER" enabled="true" />
<object-type name="DATABASE TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="false" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="JAVA CLASS" enabled="true" />
<object-type name="INNER CLASS" enabled="true" />
<object-type name="JAVA FIELD" enabled="true" />
<object-type name="JAVA METHOD" enabled="true" />
<object-type name="JAVA PARAMETER" enabled="true" />
<object-type name="DIMENSION" enabled="false" />
<object-type name="CLUSTER" enabled="false" />
<object-type name="DBLINK" enabled="false" />
<object-type name="CREDENTIAL" enabled="false" />
</lookup-objects>
<force-database-load value="false" />
<prompt-connection-selection value="true" />
<prompt-schema-selection value="true" />
</lookup-filters>
</navigation-settings>
<dataset-grid-settings>
<general>
<enable-zooming value="true" />
<enable-column-tooltip value="true" />
</general>
<sorting>
<nulls-first value="true" />
<max-sorting-columns value="4" />
</sorting>
<audit-columns>
<column-names value="" />
<visible value="true" />
<editable value="false" />
</audit-columns>
</dataset-grid-settings>
<dataset-editor-settings>
<text-editor-popup>
<active value="false" />
<active-if-empty value="false" />
<data-length-threshold value="100" />
<popup-delay value="1000" />
</text-editor-popup>
<values-actions-popup>
<show-popup-button value="true" />
<element-count-threshold value="1000" />
<data-length-threshold value="250" />
</values-actions-popup>
<general>
<fetch-block-size value="100" />
<fetch-timeout value="30" />
<trim-whitespaces value="true" />
<convert-empty-strings-to-null value="true" />
<select-content-on-cell-edit value="true" />
<large-value-preview-active value="true" />
</general>
<filters>
<prompt-filter-dialog value="true" />
<default-filter-type value="BASIC" />
</filters>
<qualified-text-editor text-length-threshold="300">
<content-types>
<content-type name="Text" enabled="true" />
<content-type name="Properties" enabled="true" />
<content-type name="XML" enabled="true" />
<content-type name="DTD" enabled="true" />
<content-type name="HTML" enabled="true" />
<content-type name="XHTML" enabled="true" />
<content-type name="CSS" enabled="true" />
<content-type name="SQL" enabled="true" />
<content-type name="PL/SQL" enabled="true" />
<content-type name="JavaScript" enabled="true" />
<content-type name="JSON" enabled="true" />
<content-type name="JSON5" enabled="true" />
<content-type name="YAML" enabled="true" />
<content-type name="C#" enabled="true" />
</content-types>
</qualified-text-editor>
<record-navigation>
<navigation-target value="VIEWER" />
</record-navigation>
</dataset-editor-settings>
<code-editor-settings>
<general>
<show-object-navigation-gutter value="false" />
<show-spec-declaration-navigation-gutter value="true" />
<enable-spellchecking value="true" />
<enable-reference-spellchecking value="false" />
</general>
<confirmations>
<save-changes value="false" />
<revert-changes value="true" />
<exit-on-changes value="ASK" />
</confirmations>
</code-editor-settings>
<code-completion-settings>
<filters>
<basic-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="false" />
<filter-element type="OBJECT" id="view" selected="false" />
<filter-element type="OBJECT" id="materialized view" selected="false" />
<filter-element type="OBJECT" id="index" selected="false" />
<filter-element type="OBJECT" id="constraint" selected="false" />
<filter-element type="OBJECT" id="trigger" selected="false" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="false" />
<filter-element type="OBJECT" id="procedure" selected="false" />
<filter-element type="OBJECT" id="function" selected="false" />
<filter-element type="OBJECT" id="package" selected="false" />
<filter-element type="OBJECT" id="type" selected="false" />
<filter-element type="OBJECT" id="dimension" selected="false" />
<filter-element type="OBJECT" id="cluster" selected="false" />
<filter-element type="OBJECT" id="dblink" selected="false" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</basic-filter>
<extended-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</extended-filter>
</filters>
<sorting enabled="true">
<sorting-element type="RESERVED_WORD" id="keyword" />
<sorting-element type="RESERVED_WORD" id="datatype" />
<sorting-element type="OBJECT" id="column" />
<sorting-element type="OBJECT" id="table" />
<sorting-element type="OBJECT" id="view" />
<sorting-element type="OBJECT" id="materialized view" />
<sorting-element type="OBJECT" id="index" />
<sorting-element type="OBJECT" id="constraint" />
<sorting-element type="OBJECT" id="trigger" />
<sorting-element type="OBJECT" id="synonym" />
<sorting-element type="OBJECT" id="sequence" />
<sorting-element type="OBJECT" id="procedure" />
<sorting-element type="OBJECT" id="function" />
<sorting-element type="OBJECT" id="package" />
<sorting-element type="OBJECT" id="type" />
<sorting-element type="OBJECT" id="dimension" />
<sorting-element type="OBJECT" id="cluster" />
<sorting-element type="OBJECT" id="dblink" />
<sorting-element type="OBJECT" id="schema" />
<sorting-element type="OBJECT" id="role" />
<sorting-element type="OBJECT" id="user" />
<sorting-element type="RESERVED_WORD" id="function" />
<sorting-element type="RESERVED_WORD" id="parameter" />
</sorting>
<format>
<enforce-code-style-case value="true" />
</format>
</code-completion-settings>
<execution-engine-settings>
<statement-execution>
<fetch-block-size value="100" />
<execution-timeout value="20" />
<debug-execution-timeout value="600" />
<focus-result value="false" />
<prompt-execution value="false" />
</statement-execution>
<script-execution>
<command-line-interfaces />
<execution-timeout value="300" />
</script-execution>
<method-execution>
<execution-timeout value="30" />
<debug-execution-timeout value="600" />
<parameter-history-size value="10" />
</method-execution>
</execution-engine-settings>
<operation-settings>
<transactions>
<uncommitted-changes>
<on-project-close value="ASK" />
<on-disconnect value="ASK" />
<on-autocommit-toggle value="ASK" />
</uncommitted-changes>
<multiple-uncommitted-changes>
<on-commit value="ASK" />
<on-rollback value="ASK" />
</multiple-uncommitted-changes>
</transactions>
<session-browser>
<disconnect-session value="ASK" />
<kill-session value="ASK" />
<reload-on-filter-change value="false" />
</session-browser>
<compiler>
<compile-type value="KEEP" />
<compile-dependencies value="ASK" />
<always-show-controls value="false" />
</compiler>
</operation-settings>
<ddl-file-settings>
<extensions>
<mapping file-type-id="VIEW" extensions="vw" />
<mapping file-type-id="TRIGGER" extensions="trg" />
<mapping file-type-id="PROCEDURE" extensions="prc" />
<mapping file-type-id="FUNCTION" extensions="fnc" />
<mapping file-type-id="PACKAGE" extensions="pkg" />
<mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
<mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
<mapping file-type-id="TYPE" extensions="tpe" />
<mapping file-type-id="TYPE_SPEC" extensions="tps" />
<mapping file-type-id="TYPE_BODY" extensions="tpb" />
<mapping file-type-id="JAVA_SOURCE" extensions="sql" />
</extensions>
<general>
<lookup-ddl-files value="true" />
<create-ddl-files value="false" />
<synchronize-ddl-files value="true" />
<use-qualified-names value="false" />
<make-scripts-rerunnable value="true" />
</general>
</ddl-file-settings>
<assistant-settings>
<credential-settings>
<credentials />
</credential-settings>
</assistant-settings>
<general-settings>
<regional-settings>
<date-format value="MEDIUM" />
<number-format value="UNGROUPED" />
<locale value="SYSTEM_DEFAULT" />
<use-custom-formats value="false" />
</regional-settings>
<environment>
<environment-types>
<environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
<environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
<environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
<environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
</environment-types>
<visibility-settings>
<connection-tabs value="true" />
<dialog-headers value="true" />
<object-editor-tabs value="true" />
<script-editor-tabs value="false" />
<execution-result-tabs value="true" />
</visibility-settings>
</environment>
</general-settings>
</component>
</project>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<component name="ContentModelUserStore">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />

8
src/.idea/.idea.Ombi/.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.Ombi/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.Ombi/riderModule.iml" />
</modules>
</component>
</project>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RiderProjectSettingsUpdater">
<option name="singleClickDiffPreview" value="1" />
<option name="vcsConfiguration" value="3" />
</component>
</project>

View file

@ -1,20 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="57001998-efde-494a-80b3-d7acfc91f770" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/Ombi/ClientApp/src/app/settings/plex/plex.component.html" beforeDir="false" afterPath="$PROJECT_DIR$/Ombi/ClientApp/src/app/settings/plex/plex.component.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Ombi.Core/Engine/Interfaces/IMusicSearchEngineV2.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Ombi.Core/Engine/V2/MusicSearchEngineV2.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Ombi.Core/Models/Search/V2/Music/ArtistInformation.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.Ombi/.idea/contentModel.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.Ombi/.idea/contentModel.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.Ombi/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.Ombi/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/config/applicationhost.config" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/config/applicationhost.config" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Ombi.Api.MusicBrainz/Models/Artist/ArtistInformation.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Ombi.Api.MusicBrainz/Models/Artist/ArtistInformation.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Ombi.DependencyInjection/IocExtensions.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Ombi.DependencyInjection/IocExtensions.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Ombi/ClientApp/src/app/media-details/components/artist/artist-details.component.ts" beforeDir="false" afterPath="$PROJECT_DIR$/Ombi/ClientApp/src/app/media-details/components/artist/artist-details.component.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Ombi/ClientApp/src/app/services/searchV2.service.ts" beforeDir="false" afterPath="$PROJECT_DIR$/Ombi/ClientApp/src/app/services/searchV2.service.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Ombi/Controllers/V2/SearchController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Ombi/Controllers/V2/SearchController.cs" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="DpaMonitoringSettings">
<option name="firstShow" value="false" />
</component>
<component name="FileEditorManager">
<leaf>
<file pinned="false" current-in-tab="false">
@ -232,75 +237,27 @@
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
</component>
<component name="GitHubPullRequestSearchHistory">{
&quot;lastFilter&quot;: {
&quot;state&quot;: &quot;OPEN&quot;,
&quot;assignee&quot;: &quot;tidusjar&quot;
}
}</component>
<component name="GitToolBoxStore">
<option name="recentBranches">
<RecentBranches>
<option name="branchesForRepo">
<list>
<RecentBranchesForRepo>
<option name="branches">
<list>
<RecentBranch>
<option name="branchName" value="wizard-database" />
<option name="lastUsedInstant" value="1735917525" />
</RecentBranch>
<RecentBranch>
<option name="branchName" value="develop" />
<option name="lastUsedInstant" value="1735917524" />
</RecentBranch>
</list>
</option>
<option name="repositoryRootUrl" value="file://$PROJECT_DIR$/.." />
</RecentBranchesForRepo>
</list>
</option>
</RecentBranches>
</option>
</component>
<component name="GithubProjectSettings">
<option name="branchProtectionPatterns">
<list>
<option value="master" />
<option value="develop" />
</list>
</option>
</component>
<component name="GithubPullRequestsUISettings">{
&quot;selectedUrlAndAccountId&quot;: {
&quot;url&quot;: &quot;https://github.com/ombi-app/ombi&quot;,
&quot;accountId&quot;: &quot;22dd09fe-fb9e-48a4-bfcc-3c152edf3f25&quot;
}
}</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/990126b794024fe2bd16aebdd37eba1d7b600/93/25662f04/ServerVersion.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/3bd4df5aff92cabbc4d630be64227073db1b8539b3a1e47786b4b189d7cdb7/DbContext.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/449b441523c469ed34ff5a5e14f0bafcd8f097aa463655303dc19048fa44ac3/EntityFrameworkServiceCollectionExtensions.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/7d81b2d4f22bee75e5438c707251ae43cb0974c207db91ffc159118c84b4eb9/ServiceProvider.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/a424e6912048b4cd25715f158e789aae24db5c2911d9e622d39bc6ac3246c6/MySqlConnectionStringBuilder.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/bd1d5c50194fea68ff3559c160230b0ab50f5acf4ce3061bffd6d62958e2182/ExceptionDispatchInfo.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/e9881a453a581134c1a18331ac1f8f1201a5382a685bf2a40777fa22619/DbContextOptions`.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Api.MusicBrainz/IMusicBrainzApi.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Api.MusicBrainz/MusicBrainzApi.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/Interfaces/IMusicSearchEngineV2.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/MusicSearchEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/RecentlyAddedEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/UserStatsEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/V2/IMultiSearchEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/V2/MultiSearchEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/V2/MusicSearchEngineV2.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Models/Search/V2/Music/ArtistInformation.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.DependencyInjection/IocExtensions.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Helpers.Tests/EmbyHelperTests.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Api.MusicBrainz/MusicBrainzApi.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Schedule.Tests/OmbiQuartzTests.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi/Controllers/V1/TokenController.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Api.MusicBrainz/Models/Artist/ArtistInformation.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi/Controllers/V2/SearchController.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.DependencyInjection/IocExtensions.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/V2/MultiSearchEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/V2/IMultiSearchEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Api.MusicBrainz/IMusicBrainzApi.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/Interfaces/IMusicSearchEngineV2.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Models/Search/V2/Music/ArtistInformation.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="mock:///Dummy.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/V2/MusicSearchEngineV2.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/RecentlyAddedEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="mock:///Dummy.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi/Controllers/V1/TokenController.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/MusicSearchEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi/Program.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Ombi.Core/Engine/UserStatsEngine.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="mock:///Dummy.cs" root0="FORCE_HIGHLIGHTING" />
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
@ -318,17 +275,12 @@
<component name="PackageJsonUpdateNotifier">
<dismissed value="$PROJECT_DIR$/Ombi/ClientApp/package.json" />
</component>
<component name="ProjectColorInfo">{
&quot;customColor&quot;: &quot;&quot;,
&quot;associatedIndex&quot;: 0
}</component>
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="1087" />
<option name="y" value="-1113" />
<option name="width" value="1400" />
<option name="height" value="1000" />
</component>
<component name="ProjectId" id="2wGwbN5gDqLwyiO1WJdlwJzZ5M9" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="2" id="Add" />
</component>
@ -391,26 +343,27 @@
<pane id="FileSystemExplorer" />
</panes>
</component>
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
<component name="PropertiesComponent">
<property name="ASKED_SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
<property name="Rider.DefaultBreakpoints.AreToggled" value="true" />
<property name="Rider.ProjectViewActivator.IsNotFirstRun" value="true" />
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="nodejs_package_manager_path" value="npm" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
".NET Launch Settings Profile.Ombi.Schedule.Tests.executor": "Run",
".NET Launch Settings Profile.Ombi.executor": "Debug",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"fb34c741-04ca-4b4f-8ea1-651a011b42c8.executor": "Debug",
"git-widget-placeholder": "watchlist-expired-notification",
"node.js.detected.package.eslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "yarn",
"vue.rearranger.settings.migration": "true"
}
}]]></component>
<component name="RunManager" selected=".NET Launch Settings Profile.Ombi">
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="RunManager" selected=".NET Launch Settings Profile.Ombi: IIS Express">
<configuration name="Ombi" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/Ombi/Ombi.csproj" />
<option name="LAUNCH_PROFILE_TFM" value=".NETCoreApp,Version=v2.2" />
@ -423,7 +376,7 @@
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<method v="2">
<option name="Build" />
<option name="Build" enabled="true" />
</method>
</configuration>
<configuration name="Ombi: IIS Express" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
@ -438,7 +391,7 @@
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<method v="2">
<option name="Build" />
<option name="Build" enabled="true" />
</method>
</configuration>
<configuration name="Ombi.Schedule.Tests" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
@ -453,7 +406,7 @@
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<method v="2">
<option name="Build" />
<option name="Build" enabled="true" />
</method>
</configuration>
<configuration name="Ombi.Schedule.Tests: IIS Express" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
@ -468,7 +421,7 @@
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<method v="2">
<option name="Build" />
<option name="Build" enabled="true" />
</method>
</configuration>
<configuration name="Ombi.Updater" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
@ -483,11 +436,10 @@
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<method v="2">
<option name="Build" />
<option name="Build" enabled="true" />
</method>
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="57001998-efde-494a-80b3-d7acfc91f770" name="Default Changelist" comment="" />
@ -496,9 +448,6 @@
<option name="presentableId" value="Default" />
<updated>1563957157468</updated>
<workItem from="1563957162999" duration="5401000" />
<workItem from="1745681294313" duration="1814000" />
<workItem from="1747080279165" duration="838000" />
<workItem from="1747082180432" duration="1994000" />
</task>
<servers />
</component>
@ -544,11 +493,7 @@
</layout>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="UnityProjectConfiguration" hasMinimizedUI="false" />
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
<option name="version" value="1" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
@ -560,7 +505,7 @@
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/Ombi/Controllers/V1/TokenController.cs</url>
<line>48</line>
<properties documentPath="$PROJECT_DIR$/Ombi/Controllers/V1/TokenController.cs">
<properties documentPath="$PROJECT_DIR$/Ombi/Controllers/V1/TokenController.cs" initialLine="48">
<startOffsets>
<option value="1518" />
</startOffsets>
@ -573,12 +518,12 @@
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/Ombi.Core/Engine/V2/MultiSearchEngine.cs</url>
<line>59</line>
<properties documentPath="$PROJECT_DIR$/Ombi.Core/Engine/V2/MultiSearchEngine.cs" containingFunctionPresentation="Method 'MultiSearch'">
<properties documentPath="$PROJECT_DIR$/Ombi.Core/Engine/V2/MultiSearchEngine.cs" initialLine="59">
<startOffsets>
<option value="2369" />
<option value="2276" />
</startOffsets>
<endOffsets>
<option value="2576" />
<option value="2316" />
</endOffsets>
</properties>
<option name="timeStamp" value="4" />
@ -586,12 +531,12 @@
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/Ombi.Core/Engine/V2/MultiSearchEngine.cs</url>
<line>49</line>
<properties documentPath="$PROJECT_DIR$/Ombi.Core/Engine/V2/MultiSearchEngine.cs" containingFunctionPresentation="Method 'MultiSearch'">
<properties documentPath="$PROJECT_DIR$/Ombi.Core/Engine/V2/MultiSearchEngine.cs" initialLine="49">
<startOffsets>
<option value="1903" />
<option value="2001" />
</startOffsets>
<endOffsets>
<option value="1945" />
<option value="2002" />
</endOffsets>
</properties>
<option name="timeStamp" value="5" />
@ -599,55 +544,16 @@
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/Ombi.Api.MusicBrainz/MusicBrainzApi.cs</url>
<line>30</line>
<properties documentPath="$PROJECT_DIR$/Ombi.Api.MusicBrainz/MusicBrainzApi.cs" containingFunctionPresentation="Method 'SearchArtist'">
<properties documentPath="$PROJECT_DIR$/Ombi.Api.MusicBrainz/MusicBrainzApi.cs" initialLine="30">
<startOffsets>
<option value="833" />
<option value="917" />
</startOffsets>
<endOffsets>
<option value="834" />
<option value="1016" />
</endOffsets>
</properties>
<option name="timeStamp" value="7" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/Ombi.Schedule/Jobs/Plex/PlexWatchlistImport.cs</url>
<line>110</line>
<properties documentPath="$PROJECT_DIR$/Ombi.Schedule/Jobs/Plex/PlexWatchlistImport.cs" containingFunctionPresentation="Method 'Execute'">
<startOffsets>
<option value="5123" />
</startOffsets>
<endOffsets>
<option value="5206" />
</endOffsets>
</properties>
<option name="timeStamp" value="10" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/Ombi.Schedule/Jobs/Plex/PlexWatchlistImport.cs</url>
<line>77</line>
<properties documentPath="$PROJECT_DIR$/Ombi.Schedule/Jobs/Plex/PlexWatchlistImport.cs" containingFunctionPresentation="Method 'Execute'">
<startOffsets>
<option value="3324" />
</startOffsets>
<endOffsets>
<option value="3365" />
</endOffsets>
</properties>
<option name="timeStamp" value="11" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/Ombi.Schedule/Jobs/Plex/PlexWatchlistImport.cs</url>
<line>100</line>
<properties documentPath="$PROJECT_DIR$/Ombi.Schedule/Jobs/Plex/PlexWatchlistImport.cs" containingFunctionPresentation="Method 'Execute'">
<startOffsets>
<option value="4602" />
</startOffsets>
<endOffsets>
<option value="4636" />
</endOffsets>
</properties>
<option name="timeStamp" value="12" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
<watches-manager>

14
src/.idea/.idea.Ombi/riderModule.iml generated Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RIDER_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$USER_HOME$/.nuget/packages/microsoft.net.test.sdk/16.0.1/build/netcoreapp1.0" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.13.0/build/netcoreapp1.0/NUnit3.TestAdapter.dll" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.13.0/build/netcoreapp1.0/NUnit3.TestAdapter.pdb" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.13.0/build/netcoreapp1.0/nunit.engine.netstandard.dll" />
<content url="file://$MODULE_DIR$/../../../CHANGELOG.md" />
<content url="file://$MODULE_DIR$/../../../appveyor.yml" />
<content url="file://$MODULE_DIR$/../../../build.cake" />
<content url="file://$MODULE_DIR$/../.." />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -1,31 +1,22 @@
{
"version": "2.0.0",
"version": "0.1.0",
"command": "dotnet",
"isShellCommand": true,
"args": [],
"tasks": [
{
"label": "build",
"type": "shell",
"command": "dotnet",
"taskName": "build",
"args": [
"build",
"${workspaceRoot}/Ombi/Ombi.csproj"
],
"problemMatcher": "$msCompile",
"group": {
"_id": "build",
"isDefault": false
}
"isBuildCommand": true,
"problemMatcher": "$msCompile"
},
{
"label": "lint",
"type": "shell",
"taskName": "lint",
"command": "npm",
"args": [
"run",
"lint"
],
"problemMatcher": []
"isShellCommand": true,
"args": ["run", "lint"]
}
]
}

View file

@ -29,6 +29,5 @@ namespace Ombi.Api.Plex
Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs);
Task<PlexWatchlistContainer> GetWatchlist(string plexToken, CancellationToken cancellationToken);
Task<PlexWatchlistMetadataContainer> GetWatchlistMetadata(string ratingKey, string plexToken, CancellationToken cancellationToken);
Task<bool> Ping(string authToken, CancellationToken cancellationToken = default);
}
}

View file

@ -22,18 +22,6 @@ namespace Ombi.Api.Plex.Models.Friends
/// </summary>
[XmlAttribute(AttributeName = "home")]
public bool HomeUser { get; set; }
[XmlElement(ElementName = "Server")]
public PlexUserServer[] Server { get; set; }
}
public class PlexUserServer
{
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
[XmlAttribute(AttributeName = "serverId")]
public string ServerId { get; set; }
}
[XmlRoot(ElementName = "MediaContainer")]

View file

@ -68,7 +68,7 @@ namespace Ombi.Api.Plex
private const string FriendsUri = "https://plex.tv/api/users";
private const string GetAccountUri = "https://plex.tv/users/account.json";
private const string ServerUri = "https://plex.tv/pms/servers.xml";
private const string WatchlistUri = "https://discover.provider.plex.tv/";
private const string WatchlistUri = "https://metadata.provider.plex.tv/";
/// <summary>
/// Sign into the Plex API
@ -320,30 +320,6 @@ namespace Ombi.Api.Plex
return result;
}
/// <summary>
/// Pings the Plex API to validate if a token is still valid
/// </summary>
/// <param name="authToken">The authentication token to validate</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>True if the token is valid, false otherwise</returns>
public async Task<bool> Ping(string authToken, CancellationToken cancellationToken = default)
{
try
{
var request = new Request("api/v2/ping", "https://plex.tv/", HttpMethod.Get);
await AddHeaders(request, authToken);
// We don't need to parse the response, just check if the request succeeds
await Api.Request(request, cancellationToken);
return true;
}
catch
{
// If the request fails (401, 403, etc.), the token is invalid
return false;
}
}
/// <summary>
/// Adds the required headers and also the authorization header

View file

@ -300,13 +300,13 @@ namespace Ombi.Core.Tests.Engine
{
UserId = "id1",
RequestType = RequestType.Movie,
RequestDate = today.AddMinutes(-1),
RequestDate = today.AddHours(-1),
},
new RequestLog
{
UserId = "id1",
RequestType = RequestType.Movie,
RequestDate = today.AddMinutes(-2),
RequestDate = today.AddHours(-2),
},
};
var repoMock = _mocker.GetMock<IRepository<RequestLog>>();

View file

@ -298,13 +298,13 @@ namespace Ombi.Core.Tests.Engine
{
UserId = "id1",
RequestType = RequestType.Album,
RequestDate = today.AddMinutes(-1),
RequestDate = today.AddHours(-1),
},
new RequestLog
{
UserId = "id1",
RequestType = RequestType.Album,
RequestDate = today.AddMinutes(-2),
RequestDate = today.AddHours(-2),
},
};
var repoMock = _mocker.GetMock<IRepository<RequestLog>>();

View file

@ -304,7 +304,7 @@ namespace Ombi.Core.Tests.Engine
{
UserId = "id1",
RequestType = RequestType.TvShow,
RequestDate = today.AddMinutes(-1),
RequestDate = today.AddHours(-1),
EpisodeCount = 1,
},
new RequestLog
@ -312,7 +312,7 @@ namespace Ombi.Core.Tests.Engine
UserId = "id1",
RequestType = RequestType.TvShow,
EpisodeCount = 1,
RequestDate = today.AddMinutes(-2),
RequestDate = today.AddHours(-2),
},
};
var repoMock = _mocker.GetMock<IRepository<RequestLog>>();
@ -345,7 +345,7 @@ namespace Ombi.Core.Tests.Engine
{
UserId = "id1",
RequestType = RequestType.TvShow,
RequestDate = today.AddMinutes(-1),
RequestDate = today.AddHours(-1),
EpisodeCount = 5,
},
new RequestLog
@ -353,7 +353,7 @@ namespace Ombi.Core.Tests.Engine
UserId = "id1",
RequestType = RequestType.TvShow,
EpisodeCount = 4,
RequestDate = today.AddMinutes(-2),
RequestDate = today.AddHours(-2),
},
};
var repoMock = _mocker.GetMock<IRepository<RequestLog>>();

View file

@ -1,52 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Ombi.Api.Plex;
namespace Ombi.Core.Authentication
{
public interface IPlexTokenKeepAliveService
{
Task<bool> KeepTokenAliveAsync(string token, CancellationToken cancellationToken);
}
public class PlexTokenKeepAliveService : IPlexTokenKeepAliveService
{
private readonly IPlexApi _plexApi;
private readonly ILogger<PlexTokenKeepAliveService> _logger;
public PlexTokenKeepAliveService(IPlexApi plexApi, ILogger<PlexTokenKeepAliveService> logger)
{
_plexApi = plexApi;
_logger = logger;
}
public async Task<bool> KeepTokenAliveAsync(string token, CancellationToken cancellationToken)
{
try
{
if (string.IsNullOrEmpty(token))
{
_logger.LogWarning("Token is null or empty");
return false;
}
// Use the Ping method to validate the token
var isValid = await _plexApi.Ping(token, cancellationToken);
if (!isValid)
{
_logger.LogWarning("Token validation failed - token may be expired or invalid");
}
return isValid;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred while keeping token alive");
return false;
}
}
}
}

View file

@ -598,13 +598,13 @@ namespace Ombi.Core.Engine
public async Task<RequestEngineResult> ApproveMovieById(int requestId, bool is4K)
{
var request = await MovieRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == requestId);
var request = await MovieRepository.Find(requestId);
return await ApproveMovie(request, is4K);
}
public async Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason, bool is4K)
{
var request = await MovieRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == modelId);
var request = await MovieRepository.Find(modelId);
if (request == null)
{
return new RequestEngineResult
@ -790,7 +790,7 @@ namespace Ombi.Core.Engine
public async Task<RequestEngineResult> ReProcessRequest(int requestId, bool is4K, CancellationToken cancellationToken)
{
var request = await MovieRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == requestId);
var request = await MovieRepository.Find(requestId);
if (request == null)
{
return new RequestEngineResult
@ -805,7 +805,7 @@ namespace Ombi.Core.Engine
public async Task<RequestEngineResult> MarkUnavailable(int modelId, bool is4K)
{
var request = await MovieRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == modelId);
var request = await MovieRepository.Find(modelId);
if (request == null)
{
return new RequestEngineResult
@ -834,7 +834,7 @@ namespace Ombi.Core.Engine
public async Task<RequestEngineResult> MarkAvailable(int modelId, bool is4K)
{
var request = await MovieRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == modelId);
var request = await MovieRepository.Find(modelId);
if (request == null)
{
return new RequestEngineResult

View file

@ -1,67 +0,0 @@
using System;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
using Ombi.Core.Models;
using Polly;
using Pomelo.EntityFrameworkCore.MySql.Storage.Internal;
namespace Ombi.Core.Helpers;
public static class DatabaseConfigurationSetup
{
public static void ConfigurePostgres(DbContextOptionsBuilder options, PerDatabaseConfiguration config)
{
options.UseNpgsql(config.ConnectionString, b =>
{
b.EnableRetryOnFailure();
}).ReplaceService<ISqlGenerationHelper, NpgsqlCaseInsensitiveSqlGenerationHelper>();
}
public static void ConfigureMySql(DbContextOptionsBuilder options, PerDatabaseConfiguration config)
{
if (string.IsNullOrEmpty(config.ConnectionString))
{
throw new ArgumentNullException("ConnectionString for the MySql/Mariadb database is empty");
}
options.UseMySql(config.ConnectionString, GetServerVersion(config.ConnectionString), b =>
{
//b.CharSetBehavior(Pomelo.EntityFrameworkCore.MySql.Infrastructure.CharSetBehavior.NeverAppend); // ##ISSUE, link to migrations?
b.EnableRetryOnFailure();
});
}
private static ServerVersion GetServerVersion(string connectionString)
{
// Workaround Windows bug, that can lead to the following exception:
//
// MySqlConnector.MySqlException (0x80004005): SSL Authentication Error
// ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
// ---> System.ComponentModel.Win32Exception (0x8009030F): The message or signature supplied for verification has been altered
//
// See https://github.com/dotnet/runtime/issues/17005#issuecomment-305848835
//
// Also workaround for the fact, that ServerVersion.AutoDetect() does not use any retrying strategy.
ServerVersion serverVersion = null;
#pragma warning disable EF1001
var retryPolicy = Policy.Handle<Exception>(exception => MySqlTransientExceptionDetector.ShouldRetryOn(exception))
#pragma warning restore EF1001
.WaitAndRetry(3, (count, context) => TimeSpan.FromMilliseconds(count * 250));
serverVersion = retryPolicy.Execute(() => serverVersion = ServerVersion.AutoDetect(connectionString));
return serverVersion;
}
public class NpgsqlCaseInsensitiveSqlGenerationHelper : NpgsqlSqlGenerationHelper
{
const string EFMigrationsHisory = "__EFMigrationsHistory";
public NpgsqlCaseInsensitiveSqlGenerationHelper(RelationalSqlGenerationHelperDependencies dependencies)
: base(dependencies) { }
public override string DelimitIdentifier(string identifier) =>
base.DelimitIdentifier(identifier == EFMigrationsHisory ? identifier : identifier.ToLower());
public override void DelimitIdentifier(StringBuilder builder, string identifier)
=> base.DelimitIdentifier(builder, identifier == EFMigrationsHisory ? identifier : identifier.ToLower());
}
}

View file

@ -1,10 +0,0 @@
namespace Ombi.Core.Helpers;
public class FileSystem : IFileSystem
{
public bool FileExists(string path)
{
return System.IO.File.Exists(path);
}
// Implement other file system operations as needed
}

View file

@ -1,7 +0,0 @@
namespace Ombi.Core.Helpers;
public interface IFileSystem
{
bool FileExists(string path);
// Add other file system operations as needed
}

View file

@ -1,40 +0,0 @@
using System.IO;
namespace Ombi.Core.Models;
public class DatabaseConfiguration
{
public const string SqliteDatabase = "Sqlite";
public DatabaseConfiguration()
{
}
public DatabaseConfiguration(string defaultSqlitePath)
{
OmbiDatabase = new PerDatabaseConfiguration(SqliteDatabase, $"Data Source={Path.Combine(defaultSqlitePath, "Ombi.db")}");
SettingsDatabase = new PerDatabaseConfiguration(SqliteDatabase, $"Data Source={Path.Combine(defaultSqlitePath, "OmbiSettings.db")}");
ExternalDatabase = new PerDatabaseConfiguration(SqliteDatabase, $"Data Source={Path.Combine(defaultSqlitePath, "OmbiExternal.db")}");
}
public PerDatabaseConfiguration OmbiDatabase { get; set; }
public PerDatabaseConfiguration SettingsDatabase { get; set; }
public PerDatabaseConfiguration ExternalDatabase { get; set; }
}
public class PerDatabaseConfiguration
{
public PerDatabaseConfiguration(string type, string connectionString)
{
Type = type;
ConnectionString = connectionString;
}
// Used in Deserialization
public PerDatabaseConfiguration()
{
}
public string Type { get; set; }
public string ConnectionString { get; set; }
}

View file

@ -182,10 +182,7 @@ namespace Ombi.Core.Senders
if (settings.SendUserTags)
{
var userTag = await GetOrCreateTag(model, settings);
if (userTag != null)
{
tags.Add(userTag.id);
}
tags.Add(userTag.id);
}
// Overrides on the request take priority
@ -201,9 +198,7 @@ namespace Ombi.Core.Senders
List<MovieResponse> movies;
// Check if the movie already exists? Since it could be unmonitored
// Get the appropriate Radarr instance settings for existence check
var existenceCheckSettings = is4k ? await _radarr4KSettings.GetSettingsAsync() : settings;
movies = await _radarrV3Api.GetMovies(existenceCheckSettings.ApiKey, existenceCheckSettings.FullUri);
movies = await _radarrV3Api.GetMovies(settings.ApiKey, settings.FullUri);
var existingMovie = movies.FirstOrDefault(x => x.tmdbId == model.TheMovieDbId);
if (existingMovie == null)
@ -251,12 +246,6 @@ namespace Ombi.Core.Senders
private async Task<Tag> GetOrCreateTag(MovieRequests model, RadarrSettings s)
{
if (model.RequestedUser == null)
{
_log.LogWarning("Cannot create tag - RequestedUser is null for movie request {MovieTitle}", model.Title);
return null;
}
var tagName = model.RequestedUser.UserName;
// Does tag exist?

View file

@ -133,14 +133,7 @@ namespace Ombi.Core.Senders
string seriesType;
int? tagToUse = null;
Logger.LogInformation("Starting SendToSonarr for series {Title} (TvDbId: {TvDbId})", model.ParentRequest.Title, model.ParentRequest.TvDbId);
Logger.LogInformation("Series type: {SeriesType}", model.SeriesType);
var profiles = await UserQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == model.RequestedUserId);
if (profiles != null)
{
Logger.LogInformation("Found user quality profile for user {UserId}", model.RequestedUserId);
}
if (model.SeriesType == SeriesType.Anime)
{
@ -148,10 +141,8 @@ namespace Ombi.Core.Senders
// For some reason, if we haven't got one use the first root folder in Sonarr
if (!int.TryParse(s.RootPathAnime, out int animePath))
{
Logger.LogWarning("Failed to parse RootPathAnime: {RootPathAnime}, falling back to main root path", s.RootPathAnime);
animePath = int.Parse(s.RootPath); // Set it to the main root folder if we have no anime folder.
}
Logger.LogInformation("Using anime path ID: {AnimePath}", animePath);
rootFolderPath = await GetSonarrRootPath(animePath, s);
languageProfileId = s.LanguageProfileAnime > 0 ? s.LanguageProfileAnime : s.LanguageProfile;
@ -163,7 +154,6 @@ namespace Ombi.Core.Senders
{
if (profiles.SonarrRootPathAnime > 0)
{
Logger.LogInformation("Using user's anime root path override: {RootPath}", profiles.SonarrRootPathAnime);
rootFolderPath = await GetSonarrRootPath(profiles.SonarrRootPathAnime, s);
}
if (profiles.SonarrQualityProfileAnime > 0)
@ -179,13 +169,11 @@ namespace Ombi.Core.Senders
int.TryParse(s.QualityProfile, out qualityToUse);
// Get the root path from the rootfolder selected.
// For some reason, if we haven't got one use the first root folder in Sonarr
Logger.LogInformation("Using standard path ID: {RootPath}", s.RootPath);
rootFolderPath = await GetSonarrRootPath(int.Parse(s.RootPath), s);
if (profiles != null)
{
if (profiles.SonarrRootPath > 0)
{
Logger.LogInformation("Using user's standard root path override: {RootPath}", profiles.SonarrRootPath);
rootFolderPath = await GetSonarrRootPath(profiles.SonarrRootPath, s);
}
if (profiles.SonarrQualityProfile > 0)
@ -205,7 +193,6 @@ namespace Ombi.Core.Senders
if (model.ParentRequest.RootFolder.HasValue && model.ParentRequest.RootFolder.Value > 0)
{
Logger.LogInformation("Using request root folder override: {RootFolder}", model.ParentRequest.RootFolder.Value);
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder.Value, s);
}
@ -214,8 +201,6 @@ namespace Ombi.Core.Senders
languageProfileId = model.ParentRequest.LanguageProfile.Value;
}
Logger.LogInformation("Final root folder path: {RootFolderPath}", rootFolderPath);
try
{
if (tagToUse.HasValue)
@ -535,36 +520,17 @@ namespace Ombi.Core.Senders
private async Task<string> GetSonarrRootPath(int pathId, SonarrSettings sonarrSettings)
{
Logger.LogInformation("Getting Sonarr root path for ID: {PathId}", pathId);
var rootFoldersResult = await SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri);
if (rootFoldersResult == null || !rootFoldersResult.Any())
{
Logger.LogError("No root folders returned from Sonarr API");
return string.Empty;
}
Logger.LogInformation("Found {Count} root folders in Sonarr", rootFoldersResult.Count());
foreach (var folder in rootFoldersResult)
{
Logger.LogDebug("Root folder - ID: {Id}, Path: {Path}", folder.id, folder.path);
}
if (pathId == 0)
{
var defaultPath = rootFoldersResult.FirstOrDefault()?.path;
Logger.LogInformation("Using first root folder as default: {Path}", defaultPath);
return defaultPath;
return rootFoldersResult.FirstOrDefault().path;
}
var matchingFolder = rootFoldersResult.FirstOrDefault(r => r.id == pathId);
if (matchingFolder != null)
foreach (var r in rootFoldersResult?.Where(r => r.id == pathId))
{
Logger.LogInformation("Found matching root folder for ID {PathId}: {Path}", pathId, matchingFolder.path);
return matchingFolder.path;
return r.path;
}
Logger.LogError("No matching root folder found for ID: {PathId}", pathId);
return string.Empty;
}
}

View file

@ -1,69 +0,0 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Ombi.Core.Helpers;
using Ombi.Core.Models;
using Ombi.Helpers;
namespace Ombi.Core.Services;
public class DatabaseConfigurationService : IDatabaseConfigurationService
{
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
public DatabaseConfigurationService(
ILogger<DatabaseConfigurationService> logger,
IFileSystem fileSystem)
{
_logger = logger;
_fileSystem = fileSystem;
}
public async Task<bool> ConfigureDatabase(string databaseType, string connectionString, CancellationToken token)
{
var i = StartupSingleton.Instance;
if (string.IsNullOrEmpty(i.StoragePath))
{
i.StoragePath = string.Empty;
}
var databaseFileLocation = Path.Combine(i.StoragePath, "database.json");
if (_fileSystem.FileExists(databaseFileLocation))
{
var error = $"The database file at '{databaseFileLocation}' already exists";
_logger.LogError(error);
return false;
}
var configuration = new DatabaseConfiguration
{
ExternalDatabase = new PerDatabaseConfiguration(databaseType, connectionString),
OmbiDatabase = new PerDatabaseConfiguration(databaseType, connectionString),
SettingsDatabase = new PerDatabaseConfiguration(databaseType, connectionString)
};
var json = JsonConvert.SerializeObject(configuration, Formatting.Indented);
_logger.LogInformation("Writing database configuration to file");
try
{
await File.WriteAllTextAsync(databaseFileLocation, json, token);
}
catch (Exception e)
{
_logger.LogError(e, "Failed to write database configuration to file");
return false;
}
_logger.LogInformation("Database configuration written to file");
return true;
}
}

View file

@ -1,11 +0,0 @@
using System.Threading;
using System.Threading.Tasks;
namespace Ombi.Core.Services;
public interface IDatabaseConfigurationService
{
const string MySqlDatabase = "MySQL";
const string PostgresDatabase = "Postgres";
Task<bool> ConfigureDatabase(string databaseType, string connectionString, CancellationToken token);
}

View file

@ -107,7 +107,6 @@ namespace Ombi.DependencyInjection
services.AddTransient<IMusicSender, MusicSender>();
services.AddTransient<IMassEmailSender, MassEmailSender>();
services.AddTransient<IPlexOAuthManager, PlexOAuthManager>();
services.AddTransient<IPlexTokenKeepAliveService, PlexTokenKeepAliveService>();
services.AddTransient<IVoteEngine, VoteEngine>();
services.AddTransient<IDemoMovieSearchEngine, DemoMovieSearchEngine>();
services.AddTransient<IDemoTvSearchEngine, DemoTvSearchEngine>();
@ -237,8 +236,6 @@ namespace Ombi.DependencyInjection
services.AddScoped<IFeatureService, FeatureService>();
services.AddTransient<IRecentlyRequestedService, RecentlyRequestedService>();
services.AddTransient<IPlexService, PlexService>();
services.AddSingleton<IFileSystem, FileSystem>();
services.AddSingleton<IDatabaseConfigurationService, DatabaseConfigurationService>();
}
public static void RegisterJobs(this IServiceCollection services)

View file

@ -14,7 +14,6 @@
IssueResolved = 9,
IssueComment = 10,
Newsletter = 11,
PartiallyAvailable = 12,
PlexWatchlistTokenExpired = 13
PartiallyAvailable = 12
}
}

View file

@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="Ensure.That" Version="10.1.0" />
<PackageReference Include="MailKit" Version="4.6.0" />
<PackageReference Include="MailKit" Version="4.1.0" />
</ItemGroup>
<ItemGroup>

View file

@ -91,12 +91,12 @@ namespace Ombi.Schedule.Tests
new Issues
{
Status = IssueStatus.Resolved,
ResovledDate = DateTime.UtcNow.AddDays(-2)
ResovledDate = DateTime.Now.AddDays(-2)
},
new Issues
{
Status = IssueStatus.Resolved,
ResovledDate = DateTime.UtcNow.AddDays(-4)
ResovledDate = DateTime.Now.AddDays(-4)
}
};

View file

@ -2,9 +2,6 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup>
@ -16,7 +13,7 @@
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="NUnit.ConsoleRunner" Version="3.15.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.2" />
<packagereference Include="Microsoft.NET.Test.Sdk" Version="17.6.2"></packagereference>
</ItemGroup>
<ItemGroup>

View file

@ -182,6 +182,8 @@ namespace Ombi.Schedule.Tests
_mocker.Verify<OmbiUserManager>(x => x.UpdateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Doesnt_Import_Banned_Users()
{
@ -245,15 +247,7 @@ namespace Ombi.Schedule.Tests
Id = "id",
Title = "title",
Username = "username",
HomeUser = true,
Server = new PlexUserServer[]
{
new PlexUserServer
{
Id = "1",
ServerId = "123"
}
}
HomeUser = true
}
}
});
@ -263,6 +257,7 @@ namespace Ombi.Schedule.Tests
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.AddToRoleAsync(It.Is<OmbiUser>(x => x.UserName == "plex"), OmbiRoles.RequestMovie))
.ReturnsAsync(IdentityResult.Success);
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Once);
@ -311,15 +306,7 @@ namespace Ombi.Schedule.Tests
{
Email = "email",
Id = "id",
Username = "plex",
Server = new PlexUserServer[]
{
new PlexUserServer
{
Id = "1",
ServerId = "123"
}
}
Username = "plex"
}
}
});
@ -344,9 +331,9 @@ namespace Ombi.Schedule.Tests
ImportPlexAdmin = false,
ImportPlexUsers = true,
DefaultRoles = new List<string>
{
OmbiRoles.RequestMovie
}
{
OmbiRoles.RequestMovie
}
});
_mocker.Setup<IPlexApi, Task<PlexUsers>>(x => x.GetUsers(It.IsAny<string>())).ReturnsAsync(new PlexUsers
{
@ -356,15 +343,7 @@ namespace Ombi.Schedule.Tests
{
Email = "email",
Id = "PLEX_ID",
Username = "user",
Server = new PlexUserServer[]
{
new PlexUserServer
{
Id = "1",
ServerId = "123"
}
}
Username = "user"
}
}
});
@ -461,98 +440,5 @@ namespace Ombi.Schedule.Tests
_mocker.Verify<IUserDeletionEngine>(x => x.DeleteUser(It.Is<OmbiUser>(x => x.ProviderUserId == "ADMIN_ID" && x.Email == "ADMIN@ADMIN.CO" && x.UserName == "Admin")), Times.Never);
}
[Test]
public async Task Import_Skips_Users_Without_Server_Access()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = false, ImportPlexUsers = true });
_mocker.Setup<IPlexApi, Task<PlexUsers>>(x => x.GetUsers(It.IsAny<string>())).ReturnsAsync(new PlexUsers
{
User = new UserFriends[]
{
new UserFriends
{
Email = "email",
Id = "NoServer",
Title = "title",
Username = "username",
Server = null
}
}
});
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Skips_Users_With_Empty_Server_Array()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = false, ImportPlexUsers = true });
_mocker.Setup<IPlexApi, Task<PlexUsers>>(x => x.GetUsers(It.IsAny<string>())).ReturnsAsync(new PlexUsers
{
User = new UserFriends[]
{
new UserFriends
{
Email = "email",
Id = "EmptyServer",
Title = "title",
Username = "username",
Server = new PlexUserServer[0]
}
}
});
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Creates_User_With_Server_Access()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = false, ImportPlexUsers = true });
_mocker.Setup<IPlexApi, Task<PlexUsers>>(x => x.GetUsers(It.IsAny<string>())).ReturnsAsync(new PlexUsers
{
User = new UserFriends[]
{
new UserFriends
{
Email = "email",
Id = "HasServer",
Title = "title",
Username = "username",
Server = new PlexUserServer[]
{
new PlexUserServer
{
Id = "1",
ServerId = "123"
}
}
}
}
});
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.CreateAsync(It.Is<OmbiUser>(x =>
x.UserName == "username" &&
x.Email == "email" &&
x.ProviderUserId == "HasServer" &&
x.UserType == UserType.PlexUser)))
.ReturnsAsync(IdentityResult.Success);
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.Is<OmbiUser>(x =>
x.UserName == "username" &&
x.Email == "email" &&
x.ProviderUserId == "HasServer" &&
x.UserType == UserType.PlexUser)), Times.Once);
}
}
}

View file

@ -20,11 +20,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Ombi.Notifications.Models;
using Ombi.Core.Notifications;
using Ombi.Helpers;
using Ombi.Core;
using Ombi.Core.Authentication;
namespace Ombi.Schedule.Tests
{
@ -40,15 +35,12 @@ namespace Ombi.Schedule.Tests
public void Setup()
{
_mocker = new AutoMocker();
var um = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { Id = "abc", Email = "email@email.com", UserType = UserType.PlexUser, MediaServerToken = "token1", UserName = "abc", NormalizedUserName = "ABC" } });
var um = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { Id = "abc", UserType = UserType.PlexUser, MediaServerToken = "token1", UserName = "abc", NormalizedUserName = "ABC" } });
_mocker.Use(um);
_context = _mocker.GetMock<IJobExecutionContext>();
_context.Setup(x => x.CancellationToken).Returns(CancellationToken.None);
// Mock the keep-alive service to return true by default
_mocker.Use<IPlexTokenKeepAliveService>(Mock.Of<IPlexTokenKeepAliveService>(s => s.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()) == Task.FromResult(true)));
_subject = _mocker.CreateInstance<PlexWatchlistImport>();
_mocker.Setup<IRepository<PlexWatchlistUserError>, IQueryable<PlexWatchlistUserError>>(x => x.GetAll()).Returns(new List<PlexWatchlistUserError>().AsQueryable().BuildMock());
_mocker.Setup<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()));
}
[Test]
@ -690,6 +682,7 @@ namespace Ombi.Schedule.Tests
[Test]
public async Task MovieRequestFromWatchList_AlreadyImported()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
{
@ -726,7 +719,7 @@ namespace Ombi.Schedule.Tests
}
});
_mocker.Setup<IExternalRepository<PlexWatchlistHistory>, IQueryable<PlexWatchlistHistory>>(x => x.GetAll()).Returns(new List<PlexWatchlistHistory> { new PlexWatchlistHistory { Id = 1, TmdbId = "123", UserId = "abc" } }.AsQueryable());
_mocker.Setup<IExternalRepository<PlexWatchlistHistory>, IQueryable<PlexWatchlistHistory>>(x => x.GetAll()).Returns(new List<PlexWatchlistHistory> { new PlexWatchlistHistory { Id = 1, TmdbId = "123" } }.AsQueryable());
await _subject.Execute(_context.Object);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()), Times.Never);
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
@ -785,99 +778,5 @@ namespace Ombi.Schedule.Tests
_mocker.Verify<IExternalRepository<PlexWatchlistHistory>>(x => x.GetAll(), Times.Once);
_mocker.Verify<IExternalRepository<PlexWatchlistHistory>>(x => x.Add(It.IsAny<PlexWatchlistHistory>()), Times.Once);
}
[Test]
public async Task AuthenticationError_NotificationsEnabled_WithEmail_SendsNotification()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true, NotifyOnWatchlistTokenExpiration = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new PlexWatchlistContainer { AuthError = true });
// Act
await _subject.Execute(_context.Object);
// Assert
_mocker.Verify<INotificationHelper>(x => x.Notify(It.Is<NotificationOptions>(n =>
n.NotificationType == NotificationType.PlexWatchlistTokenExpired &&
n.Recipient == "email@email.com" &&
n.Substitutes["UserName"] == "abc"
)), Times.Once);
}
[Test]
public async Task AuthenticationError_NotificationsDisabled_WithEmail_DoesNotSendNotification()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true, NotifyOnWatchlistTokenExpiration = false });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new PlexWatchlistContainer { AuthError = true });
// Act
await _subject.Execute(_context.Object);
// Assert
_mocker.Verify<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()), Times.Never);
}
[Test]
public async Task AuthenticationError_NotificationsEnabled_NoEmail_DoesNotSendNotification()
{
// Arrange
var user = new OmbiUser { Id = "abc", UserType = UserType.PlexUser, MediaServerToken = "token1", UserName = "abc", NormalizedUserName = "ABC" };
var um = MockHelper.MockUserManager(new List<OmbiUser> { user });
_mocker.Use(um);
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true, NotifyOnWatchlistTokenExpiration = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new PlexWatchlistContainer { AuthError = true });
_subject = _mocker.CreateInstance<PlexWatchlistImport>();
// Act
await _subject.Execute(_context.Object);
// Assert
_mocker.Verify<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()), Times.Never);
}
[Test]
public async Task SkipsUserIfTokenKeepAliveFails()
{
// Arrange: Set up the keep-alive service to return false (token invalid/expired)
var keepAliveMock = new Mock<IPlexTokenKeepAliveService>();
keepAliveMock.Setup(x => x.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(false);
_mocker.Use(keepAliveMock.Object);
_subject = _mocker.CreateInstance<PlexWatchlistImport>();
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
// Act
await _subject.Execute(_context.Object);
// Assert: Should not attempt to import watchlist if keep-alive fails
keepAliveMock.Verify(x => x.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
_mocker.Verify<IPlexApi>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
_mocker.Verify<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()), Times.Never); // or Times.Once if notification is expected
}
[Test]
public async Task CallsKeepAliveForEachPlexUser()
{
// Arrange: Multiple Plex users
var users = new List<OmbiUser>
{
new OmbiUser { Id = "abc1", UserType = UserType.PlexUser, MediaServerToken = "abc1", UserName = "abc1", NormalizedUserName = "ABC1" },
new OmbiUser { Id = "abc2", UserType = UserType.PlexUser, MediaServerToken = "abc2", UserName = "abc2", NormalizedUserName = "ABC2" },
};
var um = MockHelper.MockUserManager(users);
_mocker.Use(um);
var keepAliveMock = new Mock<IPlexTokenKeepAliveService>();
keepAliveMock.Setup(x => x.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(true);
_mocker.Use(keepAliveMock.Object);
_subject = _mocker.CreateInstance<PlexWatchlistImport>();
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
// Act
await _subject.Execute(_context.Object);
// Assert: KeepAlive should be called for each user
keepAliveMock.Verify(x => x.KeepTokenAliveAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(users.Count));
}
}
}

View file

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:62604/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Ombi.Schedule.Tests": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:62605/"
}
}
}

View file

@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging;
using Ombi.Api.Emby;
using Ombi.Api.Jellyfin;
using Ombi.Api.Plex;
using Ombi.Api.Plex.Models;
using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Api.TvMaze;
@ -287,18 +286,7 @@ namespace Ombi.Schedule.Jobs.Ombi
continue;
}
var servers = settings.Servers[0];
PlexMetadata metaData = null;
try
{
metaData = await _plexApi.GetMetadata(servers.PlexAuthToken, settings.Servers[0].FullUri, movie.Key);
}
catch (Exception e)
{
_log.LogError($"Could not find the metadata for title: '{movie.Title}', skipping");
_log.LogDebug(e, $"Could not find the metadata for title: '{movie.Title}', skipping");
continue;
}
var metaData = await _plexApi.GetMetadata(servers.PlexAuthToken, settings.Servers[0].FullUri, movie.Key);
var guids = new List<string>();
var meta = metaData.MediaContainer.Metadata.FirstOrDefault();

View file

@ -304,13 +304,6 @@ namespace Ombi.Schedule.Jobs.Plex
var existing = await Repo.GetFirstContentByCustom(x => x.Title == movie.title
&& x.ReleaseYear == movie.year.ToString()
&& x.Type == MediaType.Movie);
if (existing == null)
{
// Let's just check the key
existing = await Repo.GetByKey(movie.ratingKey);
}
if (existing != null)
{
// We need to see if this is a different quality,
@ -347,7 +340,13 @@ namespace Ombi.Schedule.Jobs.Plex
Logger.LogDebug($"We already have movie {movie.title}");
continue;
}
}
//var hasSameKey = await Repo.GetByKey(movie.ratingKey);
//if (hasSameKey != null)
//{
// await Repo.Delete(hasSameKey);
//}
Logger.LogDebug("Adding movie {0}", movie.title);
var guids = new List<string>();

View file

@ -120,13 +120,6 @@ namespace Ombi.Schedule.Jobs.Plex
foreach (var plexUser in users.User)
{
// Skip users without server access
if (plexUser.Server == null || !plexUser.Server.Any())
{
_log.LogInformation($"Skipping user {plexUser.Username ?? plexUser.Id} as they have no server access");
continue;
}
// Check if we should import this user
if (userManagementSettings.BannedPlexUserIds.Contains(plexUser.Id))
{

View file

@ -22,11 +22,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Ombi.Notifications.Models;
using Ombi.Core.Notifications;
using Microsoft.AspNetCore.Identity;
using Ombi.Store.Repository.Requests;
using Ombi.Core;
namespace Ombi.Schedule.Jobs.Plex
{
@ -42,13 +37,11 @@ namespace Ombi.Schedule.Jobs.Plex
private readonly IExternalRepository<PlexWatchlistHistory> _watchlistRepo;
private readonly IRepository<PlexWatchlistUserError> _userError;
private readonly IMovieDbApi _movieDbApi;
private readonly INotificationHelper _notificationHelper;
private readonly IPlexTokenKeepAliveService _tokenKeepAliveService;
public PlexWatchlistImport(IPlexApi plexApi, ISettingsService<PlexSettings> settings, OmbiUserManager ombiUserManager,
IMovieRequestEngine movieRequestEngine, ITvRequestEngine tvRequestEngine, INotificationHubService notificationHubService,
ILogger<PlexWatchlistImport> logger, IExternalRepository<PlexWatchlistHistory> watchlistRepo, IRepository<PlexWatchlistUserError> userError,
IMovieDbApi movieDbApi, INotificationHelper notificationHelper, IPlexTokenKeepAliveService tokenKeepAliveService)
IMovieDbApi movieDbApi)
{
_plexApi = plexApi;
_settings = settings;
@ -60,8 +53,6 @@ namespace Ombi.Schedule.Jobs.Plex
_watchlistRepo = watchlistRepo;
_userError = userError;
_movieDbApi = movieDbApi;
_notificationHelper = notificationHelper;
_tokenKeepAliveService = tokenKeepAliveService;
}
public async Task Execute(IJobExecutionContext context)
@ -99,36 +90,6 @@ namespace Ombi.Schedule.Jobs.Plex
}
_logger.LogDebug($"Starting Watchlist Import for {user.UserName} with token {user.MediaServerToken}");
// Keep the token alive before attempting watchlist import
var keepAliveSuccess = await _tokenKeepAliveService.KeepTokenAliveAsync(user.MediaServerToken, context?.CancellationToken ?? CancellationToken.None);
if (!keepAliveSuccess)
{
_logger.LogWarning($"Token for user '{user.UserName}' is invalid or expired (keep-alive failed). Recording error and skipping.");
await _userError.Add(new PlexWatchlistUserError
{
UserId = user.Id,
MediaServerToken = user.MediaServerToken,
});
// Send notification to user about token expiration
if (settings.NotifyOnWatchlistTokenExpiration && !string.IsNullOrEmpty(user.Email))
{
var notificationModel = new NotificationOptions
{
NotificationType = NotificationType.PlexWatchlistTokenExpired,
Recipient = user.Email,
DateTime = DateTime.Now,
Substitutes = new Dictionary<string, string>
{
{ "UserName", user.UserName }
}
};
await _notificationHelper.Notify(notificationModel);
}
continue;
}
var watchlist = await _plexApi.GetWatchlist(user.MediaServerToken, context?.CancellationToken ?? CancellationToken.None);
if (watchlist?.AuthError ?? false)
{
@ -138,22 +99,6 @@ namespace Ombi.Schedule.Jobs.Plex
UserId = user.Id,
MediaServerToken = user.MediaServerToken,
});
// Send notification to user about token expiration
if (settings.NotifyOnWatchlistTokenExpiration && !string.IsNullOrEmpty(user.Email))
{
var notificationModel = new NotificationOptions
{
NotificationType = NotificationType.PlexWatchlistTokenExpired,
Recipient = user.Email,
DateTime = DateTime.Now,
Substitutes = new Dictionary<string, string>
{
{ "UserName", user.UserName }
}
};
await _notificationHelper.Notify(notificationModel);
}
continue;
}
if (watchlist == null || !(watchlist.MediaContainer?.Metadata?.Any() ?? false))
@ -183,7 +128,7 @@ namespace Ombi.Schedule.Jobs.Plex
}
// Check to see if we have already imported this item
var alreadyImported = _watchlistRepo.GetAll().Any(x => x.TmdbId == providerIds.TheMovieDb && x.UserId == user.Id);
var alreadyImported = _watchlistRepo.GetAll().Any(x => x.TmdbId == providerIds.TheMovieDb);
if (alreadyImported)
{
_logger.LogDebug($"{item.title} already imported via Plex WatchList, skipping");
@ -257,14 +202,14 @@ namespace Ombi.Schedule.Jobs.Plex
if (response.ErrorCode == ErrorCode.AlreadyRequested)
{
_logger.LogDebug($"Movie already requested for user '{user.UserName}'");
await AddToHistory(theMovieDbId, user.Id);
await AddToHistory(theMovieDbId);
return;
}
_logger.LogInformation($"Error adding title from PlexWatchlist for user '{user.UserName}'. Message: '{response.ErrorMessage}'");
}
else
{
await AddToHistory(theMovieDbId, user.Id);
await AddToHistory(theMovieDbId);
_logger.LogInformation($"Added title from PlexWatchlist for user '{user.UserName}'. {response.Message}");
}
@ -285,26 +230,24 @@ namespace Ombi.Schedule.Jobs.Plex
if (response.ErrorCode == ErrorCode.AlreadyRequested)
{
_logger.LogDebug($"Show already requested for user '{user.UserName}'");
await AddToHistory(theMovieDbId, user.Id);
await AddToHistory(theMovieDbId);
return;
}
_logger.LogInformation($"Error adding title from PlexWatchlist for user '{user.UserName}'. Message: '{response.ErrorMessage}'");
}
else
{
await AddToHistory(theMovieDbId, user.Id);
await AddToHistory(theMovieDbId);
_logger.LogInformation($"Added title from PlexWatchlist for user '{user.UserName}'. {response.Message}");
}
}
private async Task AddToHistory(int theMovieDbId, string userId)
private async Task AddToHistory(int theMovieDbId)
{
// Add to the watchlist history
var history = new PlexWatchlistHistory
{
TmdbId = theMovieDbId.ToString(),
AddedAt = DateTime.UtcNow,
UserId = userId
TmdbId = theMovieDbId.ToString()
};
await _watchlistRepo.Add(history);
}

View file

@ -9,7 +9,6 @@ namespace Ombi.Core.Settings.Models.External
public bool Enable { get; set; }
public bool EnableWatchlistImport { get; set; }
public bool MonitorAll { get; set; }
public bool NotifyOnWatchlistTokenExpiration { get; set; }
/// <summary>
/// This is the ClientId for OAuth
/// </summary>

View file

@ -217,16 +217,6 @@ namespace Ombi.Store.Context
Enabled = true,
};
break;
case NotificationType.PlexWatchlistTokenExpired:
notificationToAdd = new NotificationTemplates
{
NotificationType = notificationType,
Message = "Hello {UserName}! Your Plex watchlist token has expired. Please re-authenticate with Ombi to continue using the watchlist feature.",
Subject = "Plex Watchlist Token Expired",
Agent = agent,
Enabled = true,
};
break;
default:
throw new ArgumentOutOfRangeException();
}

View file

@ -1,16 +0,0 @@
using Microsoft.EntityFrameworkCore;
namespace Ombi.Store.Context.Postgres
{
public sealed class ExternalPostgresContext : ExternalContext
{
private static bool _created;
public ExternalPostgresContext(DbContextOptions<ExternalPostgresContext> options) : base(options)
{
if (_created) return;
_created = true;
Database.Migrate();
}
}
}

View file

@ -1,22 +0,0 @@
using Microsoft.EntityFrameworkCore;
namespace Ombi.Store.Context.Postgres
{
public sealed class OmbiPostgresContext : OmbiContext
{
private static bool _created;
public OmbiPostgresContext(DbContextOptions<OmbiPostgresContext> options) : base(options)
{
if (_created) return;
_created = true;
Database.Migrate();
}
public override void Dispose()
{
base.Dispose();
}
}
}

View file

@ -1,17 +0,0 @@
using System;
using System.Runtime.CompilerServices;
namespace Ombi.Store.Context.Postgres;
public static class PostgresModuleInitializer
{
#pragma warning disable CA2255
// This is required to ensure that Npgsql uses a timestamp behavior that does not require a timezone
// Reference: https://stackoverflow.com/a/73586129
[ModuleInitializer]
#pragma warning restore CA2255
public static void Initialize()
{
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
}
}

View file

@ -1,16 +0,0 @@
using Microsoft.EntityFrameworkCore;
namespace Ombi.Store.Context.Postgres
{
public sealed class SettingsPostgresContext : SettingsContext
{
private static bool _created;
public SettingsPostgresContext(DbContextOptions<SettingsPostgresContext> options) : base(options)
{
if (_created) return;
_created = true;
Database.Migrate();
}
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities
{
@ -7,7 +6,5 @@ namespace Ombi.Store.Entities
public class PlexWatchlistHistory : Entity
{
public string TmdbId { get; set; }
public string UserId { get; set; }
public DateTime AddedAt { get; set; }
}
}

View file

@ -44,21 +44,6 @@ namespace Ombi.Store.Entities.Requests
public DateTime MarkedAsDenied4K { get; set; }
public string DeniedReason4K { get; set; }
[NotMapped]
public RequestCombination RequestCombination
{
get
{
if (Has4KRequest && RequestedDate != default)
{
return RequestCombination.Both;
}
if (Has4KRequest) { return RequestCombination.FourK; }
return RequestCombination.Normal;
}
}
/// <summary>
/// Only Use for setting the Language Code, Use the LanguageCode property for reading

View file

@ -1,9 +0,0 @@
namespace Ombi.Store.Entities.Requests
{
public enum RequestCombination
{
Normal,
FourK,
Both
}
}

View file

@ -27,48 +27,3 @@ If running migrations for any db provider other than Sqlite, then ensure the dat
cd src/Ombi.Store
dotnet ef migrations add <name> --context <context> --startup-project ../Ombi/Ombi.csproj
```
docker run -d \
--name some-postgres \
-e POSTGRES_PASSWORD=ombi \
-e POSTGRES_USER=ombi \
-e POSTGRES_DB=ombi \
postgres
### MySql example
```
{
"OmbiDatabase": {
"Type": "MySQL",
"ConnectionString": "Server=192.168.68.118;Port=3306;Database=ombiNew;User=ombi"
},
"SettingsDatabase": {
"Type": "MySQL",
"ConnectionString": "Server=192.168.68.118;Port=3306;Database=ombiNew;User=ombi"
},
"ExternalDatabase": {
"Type": "MySQL",
"ConnectionString": "Server=192.168.68.118;Port=3306;Database=ombiNew;User=ombi"
}
}
```
### Postgres Example
```
{
"OmbiDatabase": {
"Type": "Postgres",
"ConnectionString": "Host=localhost;Port=5432;Database=ombi;Username=ombi;Password=ombi"
},
"SettingsDatabase": {
"Type": "Postgres",
"ConnectionString": "Host=localhost;Port=5432;Database=ombi;Username=ombi;Password=ombi"
},
"ExternalDatabase": {
"Type": "Postgres",
"ConnectionString": "Host=localhost;Port=5432;Database=ombi;Username=ombi;Password=ombi"
}
}
```

View file

@ -20,13 +20,5 @@ INSERT INTO AspNetRoles(Id, ConcurrencyStamp, Name, NormalizedName)
SELECT '{Guid.NewGuid()}','{Guid.NewGuid()}','{role}', '{role.ToUpper()}'
WHERE NOT EXISTS(SELECT 1 FROM AspNetRoles WHERE Name = '{role}');");
}
public static void InsertRolePostgres(this MigrationBuilder mb, string role)
{
mb.Sql($@"
INSERT INTO public.""AspNetRoles""(""Id"", ""ConcurrencyStamp"", ""Name"", ""NormalizedName"")
SELECT '{Guid.NewGuid()}','{Guid.NewGuid()}','{role}', '{role.ToUpper()}'
WHERE NOT EXISTS(SELECT 1 FROM public.""AspNetRoles"" WHERE ""Name"" = '{role}');");
}
}
}

View file

@ -1,635 +0,0 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Ombi.Store.Context.MySql;
#nullable disable
namespace Ombi.Store.Migrations.ExternalMySql
{
[DbContext(typeof(ExternalMySqlContext))]
[Migration("20240909082427_WatchListUserId")]
partial class WatchListUserId
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("CouchPotatoCache");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<string>("EmbyId")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<bool>("Has4K")
.HasColumnType("tinyint(1)");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("ProviderId")
.HasColumnType("longtext");
b.Property<string>("Quality")
.HasColumnType("longtext");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.Property<int>("Type")
.HasColumnType("int");
b.Property<string>("Url")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("EmbyContent");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<string>("EmbyId")
.HasColumnType("longtext");
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("ParentId")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderId")
.HasColumnType("longtext");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("EmbyEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("Has4K")
.HasColumnType("tinyint(1)");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("JellyfinId")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<string>("ProviderId")
.HasColumnType("longtext");
b.Property<string>("Quality")
.HasColumnType("longtext");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.Property<int>("Type")
.HasColumnType("int");
b.Property<string>("Url")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("JellyfinContent");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("JellyfinId")
.HasColumnType("longtext");
b.Property<string>("ParentId")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderId")
.HasColumnType("longtext");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("JellyfinEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<int>("ArtistId")
.HasColumnType("int");
b.Property<string>("ForeignAlbumId")
.HasColumnType("longtext");
b.Property<bool>("Monitored")
.HasColumnType("tinyint(1)");
b.Property<decimal>("PercentOfTracks")
.HasColumnType("decimal(65,30)");
b.Property<DateTime>("ReleaseDate")
.HasColumnType("datetime(6)");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<int>("TrackCount")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("LidarrAlbumCache");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("ArtistId")
.HasColumnType("int");
b.Property<string>("ArtistName")
.HasColumnType("longtext");
b.Property<string>("ForeignArtistId")
.HasColumnType("longtext");
b.Property<bool>("Monitored")
.HasColumnType("tinyint(1)");
b.HasKey("Id");
b.ToTable("LidarrArtistCache");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<string>("GrandparentKey")
.HasColumnType("varchar(255)");
b.Property<string>("Key")
.HasColumnType("longtext");
b.Property<string>("ParentKey")
.HasColumnType("longtext");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<string>("Title")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("GrandparentKey");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ParentKey")
.HasColumnType("longtext");
b.Property<string>("PlexContentId")
.HasColumnType("longtext");
b.Property<int?>("PlexServerContentId")
.HasColumnType("int");
b.Property<string>("SeasonKey")
.HasColumnType("longtext");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("PlexServerContentId");
b.ToTable("PlexSeasonsContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("Has4K")
.HasColumnType("tinyint(1)");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<string>("Quality")
.HasColumnType("longtext");
b.Property<string>("ReleaseYear")
.HasColumnType("longtext");
b.Property<int?>("RequestId")
.HasColumnType("int");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.Property<int>("Type")
.HasColumnType("int");
b.Property<string>("Url")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("PlexServerContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexWatchlistHistory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<string>("TmdbId")
.HasColumnType("longtext");
b.Property<string>("UserId")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("PlexWatchlistHistory");
});
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<bool>("Has4K")
.HasColumnType("tinyint(1)");
b.Property<bool>("HasFile")
.HasColumnType("tinyint(1)");
b.Property<bool>("HasRegular")
.HasColumnType("tinyint(1)");
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("RadarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("TvDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SickRageCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<int>("TvDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SickRageEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
b.Property<int>("TvDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SonarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<bool>("HasFile")
.HasColumnType("tinyint(1)");
b.Property<int>("MovieDbId")
.HasColumnType("int");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<int>("TvDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SonarrEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
b.Property<string>("UserId")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("UserPlayedEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
b.Property<string>("UserId")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("UserPlayedMovie");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("EmbyId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.JellyfinContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("JellyfinId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
.WithMany("Episodes")
.HasForeignKey("GrandparentKey")
.HasPrincipalKey("Key");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", null)
.WithMany("Seasons")
.HasForeignKey("PlexServerContentId");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Navigation("Episodes");
b.Navigation("Seasons");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,366 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Ombi.Store.Migrations.ExternalMySql
{
/// <inheritdoc />
public partial class WatchListUserId : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "UserPlayedMovie",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "UserPlayedEpisode",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "SonarrEpisodeCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "SonarrCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "SickRageEpisodeCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "SickRageCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "RadarrCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "PlexWatchlistHistory",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AddColumn<DateTime>(
name: "AddedAt",
table: "PlexWatchlistHistory",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<string>(
name: "UserId",
table: "PlexWatchlistHistory",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "PlexServerContent",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "PlexSeasonsContent",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "PlexEpisode",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "LidarrArtistCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "LidarrAlbumCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "JellyfinEpisode",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "JellyfinContent",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "EmbyEpisode",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "EmbyContent",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "CouchPotatoCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AddedAt",
table: "PlexWatchlistHistory");
migrationBuilder.DropColumn(
name: "UserId",
table: "PlexWatchlistHistory");
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "UserPlayedMovie",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "UserPlayedEpisode",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "SonarrEpisodeCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "SonarrCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "SickRageEpisodeCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "SickRageCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "RadarrCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "PlexWatchlistHistory",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "PlexServerContent",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "PlexSeasonsContent",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "PlexEpisode",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "LidarrArtistCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "LidarrAlbumCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "JellyfinEpisode",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "JellyfinContent",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "EmbyEpisode",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "EmbyContent",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "CouchPotatoCache",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
}
}
}

View file

@ -2,7 +2,6 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Ombi.Store.Context.MySql;
@ -17,19 +16,15 @@ namespace Ombi.Store.Migrations.ExternalMySql
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.5")
.HasAnnotation("ProductVersion", "6.0.9")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
@ -44,8 +39,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
@ -91,8 +84,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
@ -136,8 +127,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
@ -183,8 +172,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
@ -228,8 +215,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
@ -265,8 +250,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("ArtistId")
.HasColumnType("int");
@ -290,8 +273,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
@ -323,8 +304,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ParentKey")
.HasColumnType("longtext");
@ -353,8 +332,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
@ -403,17 +380,9 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<string>("TmdbId")
.HasColumnType("longtext");
b.Property<string>("UserId")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("PlexWatchlistHistory");
@ -425,8 +394,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<bool>("Has4K")
.HasColumnType("tinyint(1)");
@ -450,8 +417,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("TvDbId")
.HasColumnType("int");
@ -466,8 +431,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
@ -488,8 +451,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
@ -507,8 +468,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
@ -535,8 +494,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
@ -560,8 +517,6 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd()
.HasColumnType("int");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("int");

View file

@ -1,628 +0,0 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Ombi.Store.Context.Postgres;
#nullable disable
namespace Ombi.Store.Migrations.ExternalPostgres
{
[DbContext(typeof(ExternalPostgresContext))]
[Migration("20231212135426_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.22")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("CouchPotatoCache");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("EmbyId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<string>("Quality")
.HasColumnType("text");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Url")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("EmbyContent");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("EmbyId")
.HasColumnType("text");
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("ParentId")
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("EmbyEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp with time zone");
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("JellyfinId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<string>("Quality")
.HasColumnType("text");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Url")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("JellyfinContent");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp with time zone");
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("JellyfinId")
.HasColumnType("text");
b.Property<string>("ParentId")
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("JellyfinEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp with time zone");
b.Property<int>("ArtistId")
.HasColumnType("integer");
b.Property<string>("ForeignAlbumId")
.HasColumnType("text");
b.Property<bool>("Monitored")
.HasColumnType("boolean");
b.Property<decimal>("PercentOfTracks")
.HasColumnType("numeric");
b.Property<DateTime>("ReleaseDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<int>("TrackCount")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("LidarrAlbumCache");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("ArtistId")
.HasColumnType("integer");
b.Property<string>("ArtistName")
.HasColumnType("text");
b.Property<string>("ForeignArtistId")
.HasColumnType("text");
b.Property<bool>("Monitored")
.HasColumnType("boolean");
b.HasKey("Id");
b.ToTable("LidarrArtistCache");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<string>("GrandparentKey")
.HasColumnType("text");
b.Property<string>("Key")
.HasColumnType("text");
b.Property<string>("ParentKey")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<string>("Title")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("GrandparentKey");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ParentKey")
.HasColumnType("text");
b.Property<string>("PlexContentId")
.HasColumnType("text");
b.Property<int?>("PlexServerContentId")
.HasColumnType("integer");
b.Property<string>("SeasonKey")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("PlexServerContentId");
b.ToTable("PlexSeasonsContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp with time zone");
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Quality")
.HasColumnType("text");
b.Property<string>("ReleaseYear")
.HasColumnType("text");
b.Property<int?>("RequestId")
.HasColumnType("integer");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Url")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("PlexServerContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexWatchlistHistory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("TmdbId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("PlexWatchlistHistory");
});
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<bool>("HasFile")
.HasColumnType("boolean");
b.Property<bool>("HasRegular")
.HasColumnType("boolean");
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("RadarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SickRageCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SickRageEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SonarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<bool>("HasFile")
.HasColumnType("boolean");
b.Property<int>("MovieDbId")
.HasColumnType("integer");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SonarrEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("UserPlayedEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("UserPlayedMovie");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("EmbyId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.JellyfinContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("JellyfinId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
.WithMany("Episodes")
.HasForeignKey("GrandparentKey")
.HasPrincipalKey("Key");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", null)
.WithMany("Seasons")
.HasForeignKey("PlexServerContentId");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Navigation("Episodes");
b.Navigation("Seasons");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,430 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Ombi.Store.Migrations.ExternalPostgres
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "CouchPotatoCache",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TheMovieDbId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CouchPotatoCache", x => x.Id);
});
migrationBuilder.CreateTable(
name: "EmbyContent",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ProviderId = table.Column<string>(type: "text", nullable: true),
EmbyId = table.Column<string>(type: "text", nullable: false),
Title = table.Column<string>(type: "text", nullable: true),
ImdbId = table.Column<string>(type: "text", nullable: true),
TvDbId = table.Column<string>(type: "text", nullable: true),
TheMovieDbId = table.Column<string>(type: "text", nullable: true),
Type = table.Column<int>(type: "integer", nullable: false),
Quality = table.Column<string>(type: "text", nullable: true),
Has4K = table.Column<bool>(type: "boolean", nullable: false),
Url = table.Column<string>(type: "text", nullable: true),
AddedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_EmbyContent", x => x.Id);
table.UniqueConstraint("AK_EmbyContent_EmbyId", x => x.EmbyId);
});
migrationBuilder.CreateTable(
name: "JellyfinContent",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ProviderId = table.Column<string>(type: "text", nullable: true),
JellyfinId = table.Column<string>(type: "text", nullable: false),
Title = table.Column<string>(type: "text", nullable: true),
ImdbId = table.Column<string>(type: "text", nullable: true),
TvDbId = table.Column<string>(type: "text", nullable: true),
TheMovieDbId = table.Column<string>(type: "text", nullable: true),
Type = table.Column<int>(type: "integer", nullable: false),
Quality = table.Column<string>(type: "text", nullable: true),
Has4K = table.Column<bool>(type: "boolean", nullable: false),
Url = table.Column<string>(type: "text", nullable: true),
AddedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_JellyfinContent", x => x.Id);
table.UniqueConstraint("AK_JellyfinContent_JellyfinId", x => x.JellyfinId);
});
migrationBuilder.CreateTable(
name: "LidarrAlbumCache",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ArtistId = table.Column<int>(type: "integer", nullable: false),
ForeignAlbumId = table.Column<string>(type: "text", nullable: true),
TrackCount = table.Column<int>(type: "integer", nullable: false),
ReleaseDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Monitored = table.Column<bool>(type: "boolean", nullable: false),
Title = table.Column<string>(type: "text", nullable: true),
PercentOfTracks = table.Column<decimal>(type: "numeric", nullable: false),
AddedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LidarrAlbumCache", x => x.Id);
});
migrationBuilder.CreateTable(
name: "LidarrArtistCache",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ArtistId = table.Column<int>(type: "integer", nullable: false),
ArtistName = table.Column<string>(type: "text", nullable: true),
ForeignArtistId = table.Column<string>(type: "text", nullable: true),
Monitored = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LidarrArtistCache", x => x.Id);
});
migrationBuilder.CreateTable(
name: "PlexServerContent",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ReleaseYear = table.Column<string>(type: "text", nullable: true),
Key = table.Column<string>(type: "text", nullable: false),
RequestId = table.Column<int>(type: "integer", nullable: true),
Title = table.Column<string>(type: "text", nullable: true),
ImdbId = table.Column<string>(type: "text", nullable: true),
TvDbId = table.Column<string>(type: "text", nullable: true),
TheMovieDbId = table.Column<string>(type: "text", nullable: true),
Type = table.Column<int>(type: "integer", nullable: false),
Quality = table.Column<string>(type: "text", nullable: true),
Has4K = table.Column<bool>(type: "boolean", nullable: false),
Url = table.Column<string>(type: "text", nullable: true),
AddedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_PlexServerContent", x => x.Id);
table.UniqueConstraint("AK_PlexServerContent_Key", x => x.Key);
});
migrationBuilder.CreateTable(
name: "PlexWatchlistHistory",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TmdbId = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PlexWatchlistHistory", x => x.Id);
});
migrationBuilder.CreateTable(
name: "RadarrCache",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TheMovieDbId = table.Column<int>(type: "integer", nullable: false),
HasFile = table.Column<bool>(type: "boolean", nullable: false),
Has4K = table.Column<bool>(type: "boolean", nullable: false),
HasRegular = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RadarrCache", x => x.Id);
});
migrationBuilder.CreateTable(
name: "SickRageCache",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TvDbId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SickRageCache", x => x.Id);
});
migrationBuilder.CreateTable(
name: "SickRageEpisodeCache",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
SeasonNumber = table.Column<int>(type: "integer", nullable: false),
EpisodeNumber = table.Column<int>(type: "integer", nullable: false),
TvDbId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SickRageEpisodeCache", x => x.Id);
});
migrationBuilder.CreateTable(
name: "SonarrCache",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TvDbId = table.Column<int>(type: "integer", nullable: false),
TheMovieDbId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SonarrCache", x => x.Id);
});
migrationBuilder.CreateTable(
name: "SonarrEpisodeCache",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
SeasonNumber = table.Column<int>(type: "integer", nullable: false),
EpisodeNumber = table.Column<int>(type: "integer", nullable: false),
TvDbId = table.Column<int>(type: "integer", nullable: false),
MovieDbId = table.Column<int>(type: "integer", nullable: false),
HasFile = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SonarrEpisodeCache", x => x.Id);
});
migrationBuilder.CreateTable(
name: "UserPlayedEpisode",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TheMovieDbId = table.Column<int>(type: "integer", nullable: false),
SeasonNumber = table.Column<int>(type: "integer", nullable: false),
EpisodeNumber = table.Column<int>(type: "integer", nullable: false),
UserId = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserPlayedEpisode", x => x.Id);
});
migrationBuilder.CreateTable(
name: "UserPlayedMovie",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TheMovieDbId = table.Column<int>(type: "integer", nullable: false),
UserId = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserPlayedMovie", x => x.Id);
});
migrationBuilder.CreateTable(
name: "EmbyEpisode",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
EmbyId = table.Column<string>(type: "text", nullable: true),
ParentId = table.Column<string>(type: "text", nullable: true),
ProviderId = table.Column<string>(type: "text", nullable: true),
AddedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
TvDbId = table.Column<string>(type: "text", nullable: true),
ImdbId = table.Column<string>(type: "text", nullable: true),
TheMovieDbId = table.Column<string>(type: "text", nullable: true),
EpisodeNumber = table.Column<int>(type: "integer", nullable: false),
SeasonNumber = table.Column<int>(type: "integer", nullable: false),
Title = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_EmbyEpisode", x => x.Id);
table.ForeignKey(
name: "FK_EmbyEpisode_EmbyContent_ParentId",
column: x => x.ParentId,
principalTable: "EmbyContent",
principalColumn: "EmbyId");
});
migrationBuilder.CreateTable(
name: "JellyfinEpisode",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
JellyfinId = table.Column<string>(type: "text", nullable: true),
ParentId = table.Column<string>(type: "text", nullable: true),
ProviderId = table.Column<string>(type: "text", nullable: true),
AddedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
TvDbId = table.Column<string>(type: "text", nullable: true),
ImdbId = table.Column<string>(type: "text", nullable: true),
TheMovieDbId = table.Column<string>(type: "text", nullable: true),
EpisodeNumber = table.Column<int>(type: "integer", nullable: false),
SeasonNumber = table.Column<int>(type: "integer", nullable: false),
Title = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_JellyfinEpisode", x => x.Id);
table.ForeignKey(
name: "FK_JellyfinEpisode_JellyfinContent_ParentId",
column: x => x.ParentId,
principalTable: "JellyfinContent",
principalColumn: "JellyfinId");
});
migrationBuilder.CreateTable(
name: "PlexEpisode",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Key = table.Column<string>(type: "text", nullable: true),
ParentKey = table.Column<string>(type: "text", nullable: true),
GrandparentKey = table.Column<string>(type: "text", nullable: true),
EpisodeNumber = table.Column<int>(type: "integer", nullable: false),
SeasonNumber = table.Column<int>(type: "integer", nullable: false),
Title = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PlexEpisode", x => x.Id);
table.ForeignKey(
name: "FK_PlexEpisode_PlexServerContent_GrandparentKey",
column: x => x.GrandparentKey,
principalTable: "PlexServerContent",
principalColumn: "Key");
});
migrationBuilder.CreateTable(
name: "PlexSeasonsContent",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
PlexContentId = table.Column<string>(type: "text", nullable: true),
SeasonNumber = table.Column<int>(type: "integer", nullable: false),
SeasonKey = table.Column<string>(type: "text", nullable: true),
ParentKey = table.Column<string>(type: "text", nullable: true),
PlexServerContentId = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PlexSeasonsContent", x => x.Id);
table.ForeignKey(
name: "FK_PlexSeasonsContent_PlexServerContent_PlexServerContentId",
column: x => x.PlexServerContentId,
principalTable: "PlexServerContent",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_EmbyEpisode_ParentId",
table: "EmbyEpisode",
column: "ParentId");
migrationBuilder.CreateIndex(
name: "IX_JellyfinEpisode_ParentId",
table: "JellyfinEpisode",
column: "ParentId");
migrationBuilder.CreateIndex(
name: "IX_PlexEpisode_GrandparentKey",
table: "PlexEpisode",
column: "GrandparentKey");
migrationBuilder.CreateIndex(
name: "IX_PlexSeasonsContent_PlexServerContentId",
table: "PlexSeasonsContent",
column: "PlexServerContentId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CouchPotatoCache");
migrationBuilder.DropTable(
name: "EmbyEpisode");
migrationBuilder.DropTable(
name: "JellyfinEpisode");
migrationBuilder.DropTable(
name: "LidarrAlbumCache");
migrationBuilder.DropTable(
name: "LidarrArtistCache");
migrationBuilder.DropTable(
name: "PlexEpisode");
migrationBuilder.DropTable(
name: "PlexSeasonsContent");
migrationBuilder.DropTable(
name: "PlexWatchlistHistory");
migrationBuilder.DropTable(
name: "RadarrCache");
migrationBuilder.DropTable(
name: "SickRageCache");
migrationBuilder.DropTable(
name: "SickRageEpisodeCache");
migrationBuilder.DropTable(
name: "SonarrCache");
migrationBuilder.DropTable(
name: "SonarrEpisodeCache");
migrationBuilder.DropTable(
name: "UserPlayedEpisode");
migrationBuilder.DropTable(
name: "UserPlayedMovie");
migrationBuilder.DropTable(
name: "EmbyContent");
migrationBuilder.DropTable(
name: "JellyfinContent");
migrationBuilder.DropTable(
name: "PlexServerContent");
}
}
}

View file

@ -1,635 +0,0 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Ombi.Store.Context.Postgres;
#nullable disable
namespace Ombi.Store.Migrations.ExternalPostgres
{
[DbContext(typeof(ExternalPostgresContext))]
[Migration("20240909071802_WatchListUserId")]
partial class WatchListUserId
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("CouchPotatoCache");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<string>("EmbyId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<string>("Quality")
.HasColumnType("text");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Url")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("EmbyContent");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<string>("EmbyId")
.HasColumnType("text");
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("ParentId")
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("EmbyEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("JellyfinId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<string>("Quality")
.HasColumnType("text");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Url")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("JellyfinContent");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("JellyfinId")
.HasColumnType("text");
b.Property<string>("ParentId")
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("JellyfinEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<int>("ArtistId")
.HasColumnType("integer");
b.Property<string>("ForeignAlbumId")
.HasColumnType("text");
b.Property<bool>("Monitored")
.HasColumnType("boolean");
b.Property<decimal>("PercentOfTracks")
.HasColumnType("numeric");
b.Property<DateTime>("ReleaseDate")
.HasColumnType("timestamp without time zone");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<int>("TrackCount")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("LidarrAlbumCache");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("ArtistId")
.HasColumnType("integer");
b.Property<string>("ArtistName")
.HasColumnType("text");
b.Property<string>("ForeignArtistId")
.HasColumnType("text");
b.Property<bool>("Monitored")
.HasColumnType("boolean");
b.HasKey("Id");
b.ToTable("LidarrArtistCache");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<string>("GrandparentKey")
.HasColumnType("text");
b.Property<string>("Key")
.HasColumnType("text");
b.Property<string>("ParentKey")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<string>("Title")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("GrandparentKey");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ParentKey")
.HasColumnType("text");
b.Property<string>("PlexContentId")
.HasColumnType("text");
b.Property<int?>("PlexServerContentId")
.HasColumnType("integer");
b.Property<string>("SeasonKey")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("PlexServerContentId");
b.ToTable("PlexSeasonsContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Quality")
.HasColumnType("text");
b.Property<string>("ReleaseYear")
.HasColumnType("text");
b.Property<int?>("RequestId")
.HasColumnType("integer");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Url")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("PlexServerContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexWatchlistHistory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<string>("TmdbId")
.HasColumnType("text");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("PlexWatchlistHistory");
});
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<bool>("HasFile")
.HasColumnType("boolean");
b.Property<bool>("HasRegular")
.HasColumnType("boolean");
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("RadarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SickRageCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SickRageEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SonarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<bool>("HasFile")
.HasColumnType("boolean");
b.Property<int>("MovieDbId")
.HasColumnType("integer");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SonarrEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("UserPlayedEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("UserPlayedMovie");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("EmbyId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.JellyfinContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("JellyfinId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
.WithMany("Episodes")
.HasForeignKey("GrandparentKey")
.HasPrincipalKey("Key");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", null)
.WithMany("Seasons")
.HasForeignKey("PlexServerContentId");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Navigation("Episodes");
b.Navigation("Seasons");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,152 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Ombi.Store.Migrations.ExternalPostgres
{
/// <inheritdoc />
public partial class WatchListUserId : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "AddedAt",
table: "PlexWatchlistHistory",
type: "timestamp without time zone",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<string>(
name: "UserId",
table: "PlexWatchlistHistory",
type: "text",
nullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "PlexServerContent",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "ReleaseDate",
table: "LidarrAlbumCache",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "LidarrAlbumCache",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "JellyfinEpisode",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "JellyfinContent",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "EmbyEpisode",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "EmbyContent",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AddedAt",
table: "PlexWatchlistHistory");
migrationBuilder.DropColumn(
name: "UserId",
table: "PlexWatchlistHistory");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "PlexServerContent",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "ReleaseDate",
table: "LidarrAlbumCache",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "LidarrAlbumCache",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "JellyfinEpisode",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "JellyfinContent",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "EmbyEpisode",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "AddedAt",
table: "EmbyContent",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
}
}
}

View file

@ -1,632 +0,0 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Ombi.Store.Context.Postgres;
#nullable disable
namespace Ombi.Store.Migrations.ExternalPostgres
{
[DbContext(typeof(ExternalPostgresContext))]
partial class ExternalPostgresContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("CouchPotatoCache");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<string>("EmbyId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<string>("Quality")
.HasColumnType("text");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Url")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("EmbyContent");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<string>("EmbyId")
.HasColumnType("text");
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("ParentId")
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("EmbyEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("JellyfinId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<string>("Quality")
.HasColumnType("text");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Url")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("JellyfinContent");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("JellyfinId")
.HasColumnType("text");
b.Property<string>("ParentId")
.HasColumnType("text");
b.Property<string>("ProviderId")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("JellyfinEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<int>("ArtistId")
.HasColumnType("integer");
b.Property<string>("ForeignAlbumId")
.HasColumnType("text");
b.Property<bool>("Monitored")
.HasColumnType("boolean");
b.Property<decimal>("PercentOfTracks")
.HasColumnType("numeric");
b.Property<DateTime>("ReleaseDate")
.HasColumnType("timestamp without time zone");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<int>("TrackCount")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("LidarrAlbumCache");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("ArtistId")
.HasColumnType("integer");
b.Property<string>("ArtistName")
.HasColumnType("text");
b.Property<string>("ForeignArtistId")
.HasColumnType("text");
b.Property<bool>("Monitored")
.HasColumnType("boolean");
b.HasKey("Id");
b.ToTable("LidarrArtistCache");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<string>("GrandparentKey")
.HasColumnType("text");
b.Property<string>("Key")
.HasColumnType("text");
b.Property<string>("ParentKey")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<string>("Title")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("GrandparentKey");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ParentKey")
.HasColumnType("text");
b.Property<string>("PlexContentId")
.HasColumnType("text");
b.Property<int?>("PlexServerContentId")
.HasColumnType("integer");
b.Property<string>("SeasonKey")
.HasColumnType("text");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("PlexServerContentId");
b.ToTable("PlexSeasonsContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<string>("ImdbId")
.HasColumnType("text");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Quality")
.HasColumnType("text");
b.Property<string>("ReleaseYear")
.HasColumnType("text");
b.Property<int?>("RequestId")
.HasColumnType("integer");
b.Property<string>("TheMovieDbId")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("TvDbId")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Url")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("PlexServerContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexWatchlistHistory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("AddedAt")
.HasColumnType("timestamp without time zone");
b.Property<string>("TmdbId")
.HasColumnType("text");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("PlexWatchlistHistory");
});
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("Has4K")
.HasColumnType("boolean");
b.Property<bool>("HasFile")
.HasColumnType("boolean");
b.Property<bool>("HasRegular")
.HasColumnType("boolean");
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("RadarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SickRageCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SickRageEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SonarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<bool>("HasFile")
.HasColumnType("boolean");
b.Property<int>("MovieDbId")
.HasColumnType("integer");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<int>("TvDbId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("SonarrEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("EpisodeNumber")
.HasColumnType("integer");
b.Property<int>("SeasonNumber")
.HasColumnType("integer");
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("UserPlayedEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("TheMovieDbId")
.HasColumnType("integer");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("UserPlayedMovie");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("EmbyId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.JellyfinContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("JellyfinId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
.WithMany("Episodes")
.HasForeignKey("GrandparentKey")
.HasPrincipalKey("Key");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", null)
.WithMany("Seasons")
.HasForeignKey("PlexServerContentId");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Navigation("Episodes");
b.Navigation("Seasons");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,594 +0,0 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Ombi.Store.Context.Sqlite;
#nullable disable
namespace Ombi.Store.Migrations.ExternalSqlite
{
[DbContext(typeof(ExternalSqliteContext))]
[Migration("20240909070705_WatchListUserId")]
partial class WatchListUserId
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.5");
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("TheMovieDbId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("CouchPotatoCache");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("AddedAt")
.HasColumnType("TEXT");
b.Property<string>("EmbyId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("Has4K")
.HasColumnType("INTEGER");
b.Property<string>("ImdbId")
.HasColumnType("TEXT");
b.Property<string>("ProviderId")
.HasColumnType("TEXT");
b.Property<string>("Quality")
.HasColumnType("TEXT");
b.Property<string>("TheMovieDbId")
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<string>("TvDbId")
.HasColumnType("TEXT");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.Property<string>("Url")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("EmbyContent");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("AddedAt")
.HasColumnType("TEXT");
b.Property<string>("EmbyId")
.HasColumnType("TEXT");
b.Property<int>("EpisodeNumber")
.HasColumnType("INTEGER");
b.Property<string>("ImdbId")
.HasColumnType("TEXT");
b.Property<string>("ParentId")
.HasColumnType("TEXT");
b.Property<string>("ProviderId")
.HasColumnType("TEXT");
b.Property<int>("SeasonNumber")
.HasColumnType("INTEGER");
b.Property<string>("TheMovieDbId")
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<string>("TvDbId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("EmbyEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("AddedAt")
.HasColumnType("TEXT");
b.Property<bool>("Has4K")
.HasColumnType("INTEGER");
b.Property<string>("ImdbId")
.HasColumnType("TEXT");
b.Property<string>("JellyfinId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ProviderId")
.HasColumnType("TEXT");
b.Property<string>("Quality")
.HasColumnType("TEXT");
b.Property<string>("TheMovieDbId")
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<string>("TvDbId")
.HasColumnType("TEXT");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.Property<string>("Url")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("JellyfinContent");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("AddedAt")
.HasColumnType("TEXT");
b.Property<int>("EpisodeNumber")
.HasColumnType("INTEGER");
b.Property<string>("ImdbId")
.HasColumnType("TEXT");
b.Property<string>("JellyfinId")
.HasColumnType("TEXT");
b.Property<string>("ParentId")
.HasColumnType("TEXT");
b.Property<string>("ProviderId")
.HasColumnType("TEXT");
b.Property<int>("SeasonNumber")
.HasColumnType("INTEGER");
b.Property<string>("TheMovieDbId")
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<string>("TvDbId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("JellyfinEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("AddedAt")
.HasColumnType("TEXT");
b.Property<int>("ArtistId")
.HasColumnType("INTEGER");
b.Property<string>("ForeignAlbumId")
.HasColumnType("TEXT");
b.Property<bool>("Monitored")
.HasColumnType("INTEGER");
b.Property<decimal>("PercentOfTracks")
.HasColumnType("TEXT");
b.Property<DateTime>("ReleaseDate")
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<int>("TrackCount")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("LidarrAlbumCache");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("ArtistId")
.HasColumnType("INTEGER");
b.Property<string>("ArtistName")
.HasColumnType("TEXT");
b.Property<string>("ForeignArtistId")
.HasColumnType("TEXT");
b.Property<bool>("Monitored")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("LidarrArtistCache");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("EpisodeNumber")
.HasColumnType("INTEGER");
b.Property<string>("GrandparentKey")
.HasColumnType("TEXT");
b.Property<string>("Key")
.HasColumnType("TEXT");
b.Property<string>("ParentKey")
.HasColumnType("TEXT");
b.Property<int>("SeasonNumber")
.HasColumnType("INTEGER");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("GrandparentKey");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ParentKey")
.HasColumnType("TEXT");
b.Property<string>("PlexContentId")
.HasColumnType("TEXT");
b.Property<int?>("PlexServerContentId")
.HasColumnType("INTEGER");
b.Property<string>("SeasonKey")
.HasColumnType("TEXT");
b.Property<int>("SeasonNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("PlexServerContentId");
b.ToTable("PlexSeasonsContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("AddedAt")
.HasColumnType("TEXT");
b.Property<bool>("Has4K")
.HasColumnType("INTEGER");
b.Property<string>("ImdbId")
.HasColumnType("TEXT");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Quality")
.HasColumnType("TEXT");
b.Property<string>("ReleaseYear")
.HasColumnType("TEXT");
b.Property<int?>("RequestId")
.HasColumnType("INTEGER");
b.Property<string>("TheMovieDbId")
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<string>("TvDbId")
.HasColumnType("TEXT");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.Property<string>("Url")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("PlexServerContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexWatchlistHistory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("AddedAt")
.HasColumnType("TEXT");
b.Property<string>("TmdbId")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("PlexWatchlistHistory");
});
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Has4K")
.HasColumnType("INTEGER");
b.Property<bool>("HasFile")
.HasColumnType("INTEGER");
b.Property<bool>("HasRegular")
.HasColumnType("INTEGER");
b.Property<int>("TheMovieDbId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("RadarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("TvDbId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("SickRageCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("EpisodeNumber")
.HasColumnType("INTEGER");
b.Property<int>("SeasonNumber")
.HasColumnType("INTEGER");
b.Property<int>("TvDbId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("SickRageEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("TheMovieDbId")
.HasColumnType("INTEGER");
b.Property<int>("TvDbId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("SonarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("EpisodeNumber")
.HasColumnType("INTEGER");
b.Property<bool>("HasFile")
.HasColumnType("INTEGER");
b.Property<int>("MovieDbId")
.HasColumnType("INTEGER");
b.Property<int>("SeasonNumber")
.HasColumnType("INTEGER");
b.Property<int>("TvDbId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("SonarrEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("EpisodeNumber")
.HasColumnType("INTEGER");
b.Property<int>("SeasonNumber")
.HasColumnType("INTEGER");
b.Property<int>("TheMovieDbId")
.HasColumnType("INTEGER");
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("UserPlayedEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("TheMovieDbId")
.HasColumnType("INTEGER");
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("UserPlayedMovie");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("EmbyId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.JellyfinContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("JellyfinId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
.WithMany("Episodes")
.HasForeignKey("GrandparentKey")
.HasPrincipalKey("Key");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", null)
.WithMany("Seasons")
.HasForeignKey("PlexServerContentId");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Navigation("Episodes");
b.Navigation("Seasons");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,40 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Ombi.Store.Migrations.ExternalSqlite
{
/// <inheritdoc />
public partial class WatchListUserId : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "AddedAt",
table: "PlexWatchlistHistory",
type: "TEXT",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<string>(
name: "UserId",
table: "PlexWatchlistHistory",
type: "TEXT",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AddedAt",
table: "PlexWatchlistHistory");
migrationBuilder.DropColumn(
name: "UserId",
table: "PlexWatchlistHistory");
}
}
}

View file

@ -15,7 +15,7 @@ namespace Ombi.Store.Migrations.ExternalSqlite
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.5");
modelBuilder.HasAnnotation("ProductVersion", "6.0.9");
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
@ -378,15 +378,9 @@ namespace Ombi.Store.Migrations.ExternalSqlite
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("AddedAt")
.HasColumnType("TEXT");
b.Property<string>("TmdbId")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("PlexWatchlistHistory");

File diff suppressed because it is too large Load diff

View file

@ -1,934 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Ombi.Store.Migrations.OmbiPostgres
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Alias = table.Column<string>(type: "text", nullable: true),
UserType = table.Column<int>(type: "integer", nullable: false),
ProviderUserId = table.Column<string>(type: "text", nullable: true),
LastLoggedIn = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
Language = table.Column<string>(type: "text", nullable: true),
StreamingCountry = table.Column<string>(type: "text", nullable: false),
MovieRequestLimit = table.Column<int>(type: "integer", nullable: true),
EpisodeRequestLimit = table.Column<int>(type: "integer", nullable: true),
MusicRequestLimit = table.Column<int>(type: "integer", nullable: true),
MovieRequestLimitType = table.Column<int>(type: "integer", nullable: true),
EpisodeRequestLimitType = table.Column<int>(type: "integer", nullable: true),
MusicRequestLimitType = table.Column<int>(type: "integer", nullable: true),
UserAccessToken = table.Column<string>(type: "text", nullable: true),
MediaServerToken = table.Column<string>(type: "text", nullable: true),
PasswordHash = table.Column<string>(type: "text", nullable: true),
SecurityStamp = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PhoneNumber = table.Column<string>(type: "text", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Audit",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
DateTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Description = table.Column<string>(type: "text", nullable: true),
AuditType = table.Column<int>(type: "integer", nullable: false),
AuditArea = table.Column<int>(type: "integer", nullable: false),
User = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Audit", x => x.Id);
});
migrationBuilder.CreateTable(
name: "IssueCategory",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_IssueCategory", x => x.Id);
});
migrationBuilder.CreateTable(
name: "NotificationTemplates",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
NotificationType = table.Column<int>(type: "integer", nullable: false),
Agent = table.Column<int>(type: "integer", nullable: false),
Subject = table.Column<string>(type: "text", nullable: true),
Message = table.Column<string>(type: "text", nullable: true),
Enabled = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_NotificationTemplates", x => x.Id);
});
migrationBuilder.CreateTable(
name: "PlexWatchlistUserError",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: true),
MediaServerToken = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PlexWatchlistUserError", x => x.Id);
});
migrationBuilder.CreateTable(
name: "RecentlyAddedLog",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Type = table.Column<int>(type: "integer", nullable: false),
ContentType = table.Column<int>(type: "integer", nullable: false),
ContentId = table.Column<int>(type: "integer", nullable: false),
EpisodeNumber = table.Column<int>(type: "integer", nullable: true),
SeasonNumber = table.Column<int>(type: "integer", nullable: true),
AlbumId = table.Column<string>(type: "text", nullable: true),
AddedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RecentlyAddedLog", x => x.Id);
});
migrationBuilder.CreateTable(
name: "RequestQueue",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RequestId = table.Column<int>(type: "integer", nullable: false),
Type = table.Column<int>(type: "integer", nullable: false),
Dts = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Error = table.Column<string>(type: "text", nullable: true),
Completed = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
RetryCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RequestQueue", x => x.Id);
});
migrationBuilder.CreateTable(
name: "TvRequests",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TvDbId = table.Column<int>(type: "integer", nullable: false),
ExternalProviderId = table.Column<int>(type: "integer", nullable: false),
ImdbId = table.Column<string>(type: "text", nullable: true),
QualityOverride = table.Column<int>(type: "integer", nullable: true),
RootFolder = table.Column<int>(type: "integer", nullable: true),
LanguageProfile = table.Column<int>(type: "integer", nullable: true),
Overview = table.Column<string>(type: "text", nullable: true),
Title = table.Column<string>(type: "text", nullable: true),
PosterPath = table.Column<string>(type: "text", nullable: true),
Background = table.Column<string>(type: "text", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Status = table.Column<string>(type: "text", nullable: true),
TotalSeasons = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_TvRequests", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RoleId = table.Column<string>(type: "text", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AlbumRequests",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ForeignAlbumId = table.Column<string>(type: "text", nullable: true),
ForeignArtistId = table.Column<string>(type: "text", nullable: true),
Disk = table.Column<string>(type: "text", nullable: true),
Cover = table.Column<string>(type: "text", nullable: true),
Rating = table.Column<decimal>(type: "numeric", nullable: false),
ReleaseDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
ArtistName = table.Column<string>(type: "text", nullable: true),
Title = table.Column<string>(type: "text", nullable: true),
Approved = table.Column<bool>(type: "boolean", nullable: false),
MarkedAsApproved = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
RequestedDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Available = table.Column<bool>(type: "boolean", nullable: false),
MarkedAsAvailable = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
RequestedUserId = table.Column<string>(type: "text", nullable: true),
Denied = table.Column<bool>(type: "boolean", nullable: true),
MarkedAsDenied = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DeniedReason = table.Column<string>(type: "text", nullable: true),
RequestType = table.Column<int>(type: "integer", nullable: false),
RequestedByAlias = table.Column<string>(type: "text", nullable: true),
Source = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AlbumRequests", x => x.Id);
table.ForeignKey(
name: "FK_AlbumRequests_AspNetUsers_RequestedUserId",
column: x => x.RequestedUserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(type: "text", nullable: false),
RoleId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(type: "text", nullable: false),
LoginProvider = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "MobileDevices",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Token = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<string>(type: "text", nullable: true),
AddedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_MobileDevices", x => x.Id);
table.ForeignKey(
name: "FK_MobileDevices_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "MovieRequests",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TheMovieDbId = table.Column<int>(type: "integer", nullable: false),
IssueId = table.Column<int>(type: "integer", nullable: true),
RootPathOverride = table.Column<int>(type: "integer", nullable: false),
QualityOverride = table.Column<int>(type: "integer", nullable: false),
Has4KRequest = table.Column<bool>(type: "boolean", nullable: false),
Approved4K = table.Column<bool>(type: "boolean", nullable: false),
MarkedAsApproved4K = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
RequestedDate4k = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Available4K = table.Column<bool>(type: "boolean", nullable: false),
MarkedAsAvailable4K = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
Denied4K = table.Column<bool>(type: "boolean", nullable: true),
MarkedAsDenied4K = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DeniedReason4K = table.Column<string>(type: "text", nullable: true),
LangCode = table.Column<string>(type: "text", nullable: true),
Title = table.Column<string>(type: "text", nullable: true),
Approved = table.Column<bool>(type: "boolean", nullable: false),
MarkedAsApproved = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
RequestedDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Available = table.Column<bool>(type: "boolean", nullable: false),
MarkedAsAvailable = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
RequestedUserId = table.Column<string>(type: "text", nullable: true),
Denied = table.Column<bool>(type: "boolean", nullable: true),
MarkedAsDenied = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DeniedReason = table.Column<string>(type: "text", nullable: true),
RequestType = table.Column<int>(type: "integer", nullable: false),
RequestedByAlias = table.Column<string>(type: "text", nullable: true),
Source = table.Column<int>(type: "integer", nullable: false),
ImdbId = table.Column<string>(type: "text", nullable: true),
Overview = table.Column<string>(type: "text", nullable: true),
PosterPath = table.Column<string>(type: "text", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DigitalReleaseDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
Status = table.Column<string>(type: "text", nullable: true),
Background = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_MovieRequests", x => x.Id);
table.ForeignKey(
name: "FK_MovieRequests_AspNetUsers_RequestedUserId",
column: x => x.RequestedUserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "NotificationUserId",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
PlayerId = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<string>(type: "text", nullable: true),
AddedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_NotificationUserId", x => x.Id);
table.ForeignKey(
name: "FK_NotificationUserId_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "RequestLog",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: true),
RequestType = table.Column<int>(type: "integer", nullable: false),
RequestDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
RequestId = table.Column<int>(type: "integer", nullable: false),
EpisodeCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RequestLog", x => x.Id);
table.ForeignKey(
name: "FK_RequestLog_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "RequestSubscription",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: true),
RequestId = table.Column<int>(type: "integer", nullable: false),
RequestType = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RequestSubscription", x => x.Id);
table.ForeignKey(
name: "FK_RequestSubscription_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Tokens",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Token = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Tokens", x => x.Id);
table.ForeignKey(
name: "FK_Tokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "UserNotificationPreferences",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: true),
Agent = table.Column<int>(type: "integer", nullable: false),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserNotificationPreferences", x => x.Id);
table.ForeignKey(
name: "FK_UserNotificationPreferences_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "UserQualityProfiles",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: true),
SonarrQualityProfileAnime = table.Column<int>(type: "integer", nullable: false),
SonarrRootPathAnime = table.Column<int>(type: "integer", nullable: false),
SonarrRootPath = table.Column<int>(type: "integer", nullable: false),
SonarrQualityProfile = table.Column<int>(type: "integer", nullable: false),
RadarrRootPath = table.Column<int>(type: "integer", nullable: false),
RadarrQualityProfile = table.Column<int>(type: "integer", nullable: false),
Radarr4KRootPath = table.Column<int>(type: "integer", nullable: false),
Radarr4KQualityProfile = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_UserQualityProfiles", x => x.Id);
table.ForeignKey(
name: "FK_UserQualityProfiles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Votes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RequestId = table.Column<int>(type: "integer", nullable: false),
VoteType = table.Column<int>(type: "integer", nullable: false),
RequestType = table.Column<int>(type: "integer", nullable: false),
UserId = table.Column<string>(type: "text", nullable: true),
Date = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Deleted = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Votes", x => x.Id);
table.ForeignKey(
name: "FK_Votes_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "ChildRequests",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ParentRequestId = table.Column<int>(type: "integer", nullable: false),
IssueId = table.Column<int>(type: "integer", nullable: true),
SeriesType = table.Column<int>(type: "integer", nullable: false),
Title = table.Column<string>(type: "text", nullable: true),
Approved = table.Column<bool>(type: "boolean", nullable: false),
MarkedAsApproved = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
RequestedDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Available = table.Column<bool>(type: "boolean", nullable: false),
MarkedAsAvailable = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
RequestedUserId = table.Column<string>(type: "text", nullable: true),
Denied = table.Column<bool>(type: "boolean", nullable: true),
MarkedAsDenied = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DeniedReason = table.Column<string>(type: "text", nullable: true),
RequestType = table.Column<int>(type: "integer", nullable: false),
RequestedByAlias = table.Column<string>(type: "text", nullable: true),
Source = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ChildRequests", x => x.Id);
table.ForeignKey(
name: "FK_ChildRequests_AspNetUsers_RequestedUserId",
column: x => x.RequestedUserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
table.ForeignKey(
name: "FK_ChildRequests_TvRequests_ParentRequestId",
column: x => x.ParentRequestId,
principalTable: "TvRequests",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Issues",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Title = table.Column<string>(type: "text", nullable: true),
RequestType = table.Column<int>(type: "integer", nullable: false),
ProviderId = table.Column<string>(type: "text", nullable: true),
RequestId = table.Column<int>(type: "integer", nullable: true),
Subject = table.Column<string>(type: "text", nullable: true),
Description = table.Column<string>(type: "text", nullable: true),
IssueCategoryId = table.Column<int>(type: "integer", nullable: false),
Status = table.Column<int>(type: "integer", nullable: false),
ResovledDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
CreatedDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UserReportedId = table.Column<string>(type: "text", nullable: true),
IssueId = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Issues", x => x.Id);
table.ForeignKey(
name: "FK_Issues_AspNetUsers_UserReportedId",
column: x => x.UserReportedId,
principalTable: "AspNetUsers",
principalColumn: "Id");
table.ForeignKey(
name: "FK_Issues_ChildRequests_IssueId",
column: x => x.IssueId,
principalTable: "ChildRequests",
principalColumn: "Id");
table.ForeignKey(
name: "FK_Issues_IssueCategory_IssueCategoryId",
column: x => x.IssueCategoryId,
principalTable: "IssueCategory",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Issues_MovieRequests_IssueId",
column: x => x.IssueId,
principalTable: "MovieRequests",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "SeasonRequests",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
SeasonNumber = table.Column<int>(type: "integer", nullable: false),
Overview = table.Column<string>(type: "text", nullable: true),
ChildRequestId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SeasonRequests", x => x.Id);
table.ForeignKey(
name: "FK_SeasonRequests_ChildRequests_ChildRequestId",
column: x => x.ChildRequestId,
principalTable: "ChildRequests",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "IssueComments",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: true),
Comment = table.Column<string>(type: "text", nullable: true),
IssuesId = table.Column<int>(type: "integer", nullable: true),
Date = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IssueComments", x => x.Id);
table.ForeignKey(
name: "FK_IssueComments_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
table.ForeignKey(
name: "FK_IssueComments_Issues_IssuesId",
column: x => x.IssuesId,
principalTable: "Issues",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "EpisodeRequests",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
EpisodeNumber = table.Column<int>(type: "integer", nullable: false),
Title = table.Column<string>(type: "text", nullable: true),
AirDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Url = table.Column<string>(type: "text", nullable: true),
Available = table.Column<bool>(type: "boolean", nullable: false),
Approved = table.Column<bool>(type: "boolean", nullable: false),
Requested = table.Column<bool>(type: "boolean", nullable: false),
SeasonId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_EpisodeRequests", x => x.Id);
table.ForeignKey(
name: "FK_EpisodeRequests_SeasonRequests_SeasonId",
column: x => x.SeasonId,
principalTable: "SeasonRequests",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AlbumRequests_RequestedUserId",
table: "AlbumRequests",
column: "RequestedUserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ChildRequests_ParentRequestId",
table: "ChildRequests",
column: "ParentRequestId");
migrationBuilder.CreateIndex(
name: "IX_ChildRequests_RequestedUserId",
table: "ChildRequests",
column: "RequestedUserId");
migrationBuilder.CreateIndex(
name: "IX_EpisodeRequests_SeasonId",
table: "EpisodeRequests",
column: "SeasonId");
migrationBuilder.CreateIndex(
name: "IX_IssueComments_IssuesId",
table: "IssueComments",
column: "IssuesId");
migrationBuilder.CreateIndex(
name: "IX_IssueComments_UserId",
table: "IssueComments",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Issues_IssueCategoryId",
table: "Issues",
column: "IssueCategoryId");
migrationBuilder.CreateIndex(
name: "IX_Issues_IssueId",
table: "Issues",
column: "IssueId");
migrationBuilder.CreateIndex(
name: "IX_Issues_UserReportedId",
table: "Issues",
column: "UserReportedId");
migrationBuilder.CreateIndex(
name: "IX_MobileDevices_UserId",
table: "MobileDevices",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_MovieRequests_RequestedUserId",
table: "MovieRequests",
column: "RequestedUserId");
migrationBuilder.CreateIndex(
name: "IX_NotificationUserId_UserId",
table: "NotificationUserId",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_RequestLog_UserId",
table: "RequestLog",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_RequestSubscription_UserId",
table: "RequestSubscription",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_SeasonRequests_ChildRequestId",
table: "SeasonRequests",
column: "ChildRequestId");
migrationBuilder.CreateIndex(
name: "IX_Tokens_UserId",
table: "Tokens",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_UserNotificationPreferences_UserId",
table: "UserNotificationPreferences",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_UserQualityProfiles_UserId",
table: "UserQualityProfiles",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Votes_UserId",
table: "Votes",
column: "UserId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AlbumRequests");
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "Audit");
migrationBuilder.DropTable(
name: "EpisodeRequests");
migrationBuilder.DropTable(
name: "IssueComments");
migrationBuilder.DropTable(
name: "MobileDevices");
migrationBuilder.DropTable(
name: "NotificationTemplates");
migrationBuilder.DropTable(
name: "NotificationUserId");
migrationBuilder.DropTable(
name: "PlexWatchlistUserError");
migrationBuilder.DropTable(
name: "RecentlyAddedLog");
migrationBuilder.DropTable(
name: "RequestLog");
migrationBuilder.DropTable(
name: "RequestQueue");
migrationBuilder.DropTable(
name: "RequestSubscription");
migrationBuilder.DropTable(
name: "Tokens");
migrationBuilder.DropTable(
name: "UserNotificationPreferences");
migrationBuilder.DropTable(
name: "UserQualityProfiles");
migrationBuilder.DropTable(
name: "Votes");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "SeasonRequests");
migrationBuilder.DropTable(
name: "Issues");
migrationBuilder.DropTable(
name: "ChildRequests");
migrationBuilder.DropTable(
name: "IssueCategory");
migrationBuilder.DropTable(
name: "MovieRequests");
migrationBuilder.DropTable(
name: "TvRequests");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}

View file

@ -1,66 +0,0 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Ombi.Store.Context.Postgres;
#nullable disable
namespace Ombi.Store.Migrations.SettingsPostgres
{
[DbContext(typeof(SettingsPostgresContext))]
[Migration("20231212135625_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.22")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ApplicationConfiguration");
});
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Content")
.HasColumnType("text");
b.Property<string>("SettingsName")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("GlobalSettings");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,50 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Ombi.Store.Migrations.SettingsPostgres
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ApplicationConfiguration",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Type = table.Column<int>(type: "integer", nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ApplicationConfiguration", x => x.Id);
});
migrationBuilder.CreateTable(
name: "GlobalSettings",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Content = table.Column<string>(type: "text", nullable: true),
SettingsName = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_GlobalSettings", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApplicationConfiguration");
migrationBuilder.DropTable(
name: "GlobalSettings");
}
}
}

View file

@ -1,64 +0,0 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Ombi.Store.Context.Postgres;
#nullable disable
namespace Ombi.Store.Migrations.SettingsPostgres
{
[DbContext(typeof(SettingsPostgresContext))]
partial class SettingsPostgresContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.22")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ApplicationConfiguration");
});
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Content")
.HasColumnType("text");
b.Property<string>("SettingsName")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("GlobalSettings");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -19,7 +19,6 @@
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.5" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="Polly" Version="7.2.3" />
@ -41,8 +40,4 @@
<LastGenOutput>Sql.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Migrations\OmbiPostgres\" />
<Folder Include="Migrations\SettingsPostgres\" />
</ItemGroup>
</Project>

View file

@ -94,7 +94,7 @@ namespace Ombi.Store.Repository
public async Task<PlexServerContent> GetByKey(string key)
{
return await Db.PlexServerContent.Include(x => x.Seasons).Include(x => x.Episodes).FirstOrDefaultAsync(x => x.Key == key);
return await Db.PlexServerContent.Include(x => x.Seasons).FirstOrDefaultAsync(x => x.Key == key);
}
public IEnumerable<PlexServerContent> GetWhereContentByCustom(Expression<Func<PlexServerContent, bool>> predicate)

View file

@ -19,7 +19,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />

View file

@ -105,6 +105,7 @@
"options": {
"tsConfig": [
"src/tsconfig.json"
"src/tsconfig.json"
],
"exclude": [
"**/node_modules/**"

View file

@ -13,26 +13,26 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^17.3.11",
"@angular/animations": "^17.2.4",
"@angular/cdk": "16.2.14",
"@angular/common": "^17.3.11",
"@angular/compiler": "^17.3.11",
"@angular/core": "^17.3.11",
"@angular/forms": "^17.3.11",
"@angular/common": "^17.2.4",
"@angular/compiler": "^17.2.4",
"@angular/core": "^17.2.4",
"@angular/forms": "^17.2.4",
"@angular/material": "^14.2.7",
"@angular/platform-browser": "^17.3.11",
"@angular/platform-browser-dynamic": "^17.3.11",
"@angular/platform-server": "^17.3.11",
"@angular/router": "^17.3.11",
"@angular/platform-browser": "^17.2.4",
"@angular/platform-browser-dynamic": "^17.2.4",
"@angular/platform-server": "^17.2.4",
"@angular/router": "^17.2.4",
"@angularclass/hmr": "^3.0.0",
"@auth0/angular-jwt": "^5.0.2",
"@fortawesome/fontawesome-free": "^6.6.0",
"@fortawesome/fontawesome-free": "^6.4.2",
"@microsoft/signalr": "^6.0.23",
"@ngx-translate/core": "^15.0.0",
"@ngx-translate/http-loader": "^8.0.0",
"@ngxs/devtools-plugin": "3.8.2",
"@ngxs/store": "3.8.2",
"@types/jquery": "^3.5.30",
"@ngx-translate/core": "^14.0.0",
"@ngx-translate/http-loader": "^7.0.0",
"@ngxs/devtools-plugin": "3.8.1",
"@ngxs/store": "3.8.1",
"@types/jquery": "^3.5.23",
"@yellowspot/ng-truncate": "^2.0.0",
"angularx-qrcode": "^16.0.0",
"bootstrap": "^4.2.1",
@ -44,13 +44,13 @@
"ng2-cookies": "^1.0.12",
"ngx-clipboard": "^16.0.0",
"ngx-date-fns": "^11.0.0",
"ngx-infinite-scroll": "^17.0.1",
"ngx-infinite-scroll": "^17.0.0",
"popper.js": "^1.14.3",
"primeicons": "^6.0.1",
"primeng": "^17.11.0",
"primeng": "^17.6.0",
"rxjs": "^7.5.4",
"ts-md5": "^1.2.7",
"zone.js": "0.14.7"
"zone.js": "0.14.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.1.3",

View file

@ -5,17 +5,9 @@
<mat-button-toggle id="{{id}}Tv" [ngClass]="{'button-active': discoverOptions === DiscoverOption.Tv}" value="{{DiscoverOption.Tv}}" class="discover-filter-button">{{'Discovery.Tv' | translate}}</mat-button-toggle>
</mat-button-toggle-group>
</div>
@defer (when discoverResults.length > 0; prefetch on idle) {
<p-carousel #carousel [numVisible]="10" [numScroll]="10" [page]="0" [value]="discoverResults" [responsiveOptions]="responsiveOptions" (onPage)="newPage()">
<ng-template let-result pTemplate="item">
<discover-card [discoverType]="discoverType" [isAdmin]="isAdmin" [result]="result" [is4kEnabled]="is4kEnabled"></discover-card>
</ng-template>
</p-carousel>
}
@placeholder(minimum 300) {
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
}
</p-carousel>

View file

@ -105,30 +105,6 @@
padding: 5px;
}
.loading-container {
display: flex;
gap: 10px;
padding: 0 20px;
margin-top: 20px;
}
.loading-container .col-2 {
flex: 0 0 auto;
width: calc(10% - 9px);
}
@media (max-width: 768px) {
.loading-container .col-2 {
width: calc(50% - 5px);
}
}
@media (max-width: 480px) {
.loading-container .col-2 {
width: calc(100% - 0px);
}
}
@media (min-width:755px){
::ng-deep .p-carousel-item{
flex: 1 0 200px !important;

View file

@ -43,7 +43,7 @@ export class CarouselListComponent implements OnInit {
get mediaTypeStorageKey() {
return "DiscoverOptions" + this.discoverType.toString();
};
private amountToLoad = 10;
private amountToLoad = 17;
private currentlyLoaded = 0;
private baseUrl: string = "";
@ -148,7 +148,6 @@ export class CarouselListComponent implements OnInit {
}
public async ngOnInit() {
this.is4kEnabled = this.featureFacade.is4kEnabled();
this.currentlyLoaded = 0;
const localDiscoverOptions = +this.storageService.get(this.mediaTypeStorageKey);
@ -156,15 +155,11 @@ export class CarouselListComponent implements OnInit {
this.discoverOptions = DiscoverOption[DiscoverOption[localDiscoverOptions]];
}
// Load initial data - just enough to fill the first carousel page
// This reduces initial API calls and improves loading performance
await this.loadData(false);
// If we don't have enough results to fill the carousel, load one more batch
if (this.discoverResults.length < 10) {
let currentIteration = 0;
while (this.discoverResults.length <= 14 && currentIteration <= 3) {
currentIteration++;
await this.loadData(false);
}
}
public async toggleChanged(event: MatButtonToggleChange) {
@ -298,6 +293,7 @@ export class CarouselListComponent implements OnInit {
}
this.discoverResults.push(...tempResults);
this.carousel.ngAfterContentInit();
this.finishLoading();
}

View file

@ -1,108 +1,51 @@
<div class="small-middle-container">
@defer (on viewport; prefetch on idle) {
<div class="section">
<h2 id="genreHeading" data-toggle="collapse" href="#genreCollapse" role="button">{{ 'Discovery.Genres' | translate }}</h2>
<genre-button-select class="collapse show" id="genreCollapse"></genre-button-select>
<div class="section">
@defer (on viewport; prefetch on idle) {
<h2 id="genreHeading" data-toggle="collapse" href="#genreCollapse" role="button">{{ 'Discovery.Genres' | translate }}</h2>
<genre-button-select class="collapse show" id="genreCollapse"></genre-button-select>
}
@placeholder {
<p-skeleton width="100%" height="2rem"></p-skeleton>
}
</div>
<div class="section">
<h2>{{ 'Discovery.RecentlyRequestedTab' | translate }}</h2>
<div>
<ombi-recently-list [id]="'recentlyRequested'"></ombi-recently-list>
</div>
} @placeholder(minimum 300) {
<div class="section">
<h2>{{ 'Discovery.Genres' | translate }}</h2>
<p-skeleton width="100%" height="60px"></p-skeleton>
</div>
}
</div>
@defer (on viewport; prefetch on idle) {
<div class="section">
<h2>{{ 'Discovery.RecentlyRequestedTab' | translate }}</h2>
<div>
<ombi-recently-list [id]="'recentlyRequested'"></ombi-recently-list>
</div>
</div>
} @placeholder(minimum 300) {
<div class="section">
<h2>{{ 'Discovery.RecentlyRequestedTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
@defer (on viewport; prefetch on idle) {
<div class="section" [hidden]="!showSeasonal">
<h2>{{ 'Discovery.SeasonalTab' | translate }}</h2>
<div>
<carousel-list
[id]="'seasonal'"
[isAdmin]="isAdmin"
[discoverType]="DiscoverType.Seasonal"
(movieCount)="setSeasonalMovieCount($event)"
></carousel-list>
</div>
<div class="section" [hidden]="!showSeasonal">
<h2>{{ 'Discovery.SeasonalTab' | translate }}</h2>
<div>
<carousel-list
[id]="'seasonal'"
[isAdmin]="isAdmin"
[discoverType]="DiscoverType.Seasonal"
(movieCount)="setSeasonalMovieCount($event)"
></carousel-list>
</div>
} @placeholder(minimum 300) {
<div class="section">
<h2>{{ 'Discovery.SeasonalTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
</div>
@defer (on viewport; prefetch on idle) {
<div class="section">
<h2>{{ 'Discovery.PopularTab' | translate }}</h2>
<div>
<carousel-list [id]="'popular'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Popular"></carousel-list>
</div>
<div class="section">
<h2>{{ 'Discovery.PopularTab' | translate }}</h2>
<div>
<carousel-list [id]="'popular'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Popular"></carousel-list>
</div>
} @placeholder(minimum 300) {
<div class="section">
<h2>{{ 'Discovery.PopularTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
</div>
@defer (on viewport; prefetch on idle) {
<div class="section">
<h2>{{ 'Discovery.TrendingTab' | translate }}</h2>
<div>
<carousel-list [id]="'trending'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Trending"></carousel-list>
</div>
<div class="section">
<h2>{{ 'Discovery.TrendingTab' | translate }}</h2>
<div>
<carousel-list [id]="'trending'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Trending"></carousel-list>
</div>
} @placeholder(minimum 300) {
<div class="section">
<h2>{{ 'Discovery.TrendingTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
</div>
@defer (on viewport; prefetch on idle) {
<div class="section">
<h2>{{ 'Discovery.UpcomingTab' | translate }}</h2>
<div>
<carousel-list [id]="'upcoming'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Upcoming"></carousel-list>
</div>
<div class="section">
<h2>{{ 'Discovery.UpcomingTab' | translate }}</h2>
<div>
<carousel-list [id]="'upcoming'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Upcoming"></carousel-list>
</div>
} @placeholder(minimum 300) {
<div class="section">
<h2>{{ 'Discovery.UpcomingTab' | translate }}</h2>
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
</div>
}
</div>
</div>

View file

@ -9,28 +9,4 @@ h2{
margin-top:40px;
margin-left:40px;
font-size: 24px;
}
.loading-container {
display: flex;
gap: 10px;
padding: 0 20px;
margin-top: 20px;
}
.loading-container .col-2 {
flex: 0 0 auto;
width: calc(10% - 9px);
}
@media (max-width: 768px) {
.loading-container .col-2 {
width: calc(50% - 5px);
}
}
@media (max-width: 480px) {
.loading-container .col-2 {
width: calc(100% - 0px);
}
}

View file

@ -1,26 +1,13 @@
@defer (when movieGenreList()) {
<div class="genre-container">
<mat-button-toggle-group name="discoverMode" (change)="toggleChanged($event, genre.type)" *ngFor="let genre of movieGenreList()"
class="discover-filter-buttons-group">
<mat-button-toggle value="{{genre.id}}" class="discover-filter-button">{{genre.name}}</mat-button-toggle>
</mat-button-toggle-group>
</div>
}
@placeholder(minimum 500) {
<p-skeleton width="100%" height="3.5rem"></p-skeleton>
}
@defer (when tvGenreList()) {
<div class="genre-container">
<mat-button-toggle-group name="discoverMode" (change)="toggleChanged($event, genre.type)" *ngFor="let genre of tvGenreList()"
class="discover-filter-buttons-group">
<mat-button-toggle value="{{genre.id}}" class="discover-filter-button">{{genre.name}}</mat-button-toggle>
</mat-button-toggle-group>
</div>
}
@placeholder(minimum 500) {
<p-skeleton width="100%" height="3.5rem"></p-skeleton>
}
<mat-spinner *ngIf="isLoading" [diameter]="30"></mat-spinner>
<div class="genre-container" *ngIf="movieGenreList$ | async as movies">
<mat-button-toggle-group name="discoverMode" (change)="toggleChanged($event, genre.type)" *ngFor="let genre of movies"
class="discover-filter-buttons-group">
<mat-button-toggle value="{{genre.id}}" class="discover-filter-button">{{genre.name}}</mat-button-toggle>
</mat-button-toggle-group>
</div>
<div class="genre-container" *ngIf="tvGenreList$ | async as tv">
<mat-button-toggle-group name="discoverMode" (change)="toggleChanged($event, genre.type)" *ngFor="let genre of tv"
class="discover-filter-buttons-group">
<mat-button-toggle value="{{genre.id}}" class="discover-filter-button">{{genre.name}}</mat-button-toggle>
</mat-button-toggle-group>
<mat-spinner *ngIf="isLoading" [diameter]="30"></mat-spinner>
</div>

View file

@ -1,11 +1,10 @@
import { Component, OnInit, computed, signal } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { SearchV2Service } from "../../../services";
import { MatButtonToggleChange } from "@angular/material/button-toggle";
import { RequestType } from "../../../interfaces";
import { AdvancedSearchDialogDataService } from "app/shared/advanced-search-dialog/advanced-search-dialog-data.service";
import { Router } from "@angular/router";
import { map, Observable } from "rxjs";
import { toSignal } from '@angular/core/rxjs-interop';
interface IGenreSelect {
name: string;
@ -18,10 +17,8 @@ interface IGenreSelect {
styleUrls: ["./genre-button-select.component.scss"],
})
export class GenreButtonSelectComponent implements OnInit {
public movieGenreList = signal<IGenreSelect[]>(null);
public tvGenreList = signal<IGenreSelect[]>(null);
public movieGenreList$: Observable<IGenreSelect[]> = null;
public tvGenreList$: Observable<IGenreSelect[]> = null;
isLoading: boolean = false;
@ -30,14 +27,8 @@ export class GenreButtonSelectComponent implements OnInit {
private router: Router) { }
public ngOnInit(): void {
this.searchService.getGenres("movie").pipe(map(x => x.slice(0, 10).map(y => ({ name: y.name, id: y.id, type: "movie" } as IGenreSelect))))
.subscribe(x => {
this.movieGenreList.set(x);
});
this.searchService.getGenres("tv").pipe(map(x => x.slice(0, 10).map(y => ({ name: y.name, id: y.id, type: "tv" } as IGenreSelect))))
.subscribe(x => {
this.tvGenreList.set(x);
});
this.movieGenreList$ = this.searchService.getGenres("movie").pipe(map(x => x.slice(0, 10).map(y => ({ name: y.name, id: y.id, type: "movie" }))));
this.tvGenreList$ = this.searchService.getGenres("tv").pipe(map(x => x.slice(0, 10).map(y => ({ name: y.name, id: y.id, type: "tv" }))));
}
public async toggleChanged(event: MatButtonToggleChange, type: "movie"|"tv") {

View file

@ -1,8 +1,9 @@
@defer (when requests(); prefetch on idle) {
<div *ngIf="requests().length > 0">
<p-carousel #carousel [value]="requests()" [numVisible]="3" [numScroll]="1"
<div *ngIf="requests$ | async as requests">
<div *ngIf="requests.length > 0">
<p-carousel #carousel [value]="requests" [numVisible]="3" [numScroll]="1"
[responsiveOptions]="responsiveOptions" [page]="0">
<ng-template let-result pTemplate="item">
@defer (on viewport; prefetch on idle) {
<ombi-detailed-card
[request]="result"
[isAdmin]="isAdmin"
@ -10,13 +11,11 @@
(onApprove)="approve(result)"
(onDeny)="deny(result)">
</ombi-detailed-card>
}
@placeholder {
<p-skeleton width="100%" height="315px"></p-skeleton>
}
</ng-template>
</p-carousel>
</div>
}@placeholder(minimum 300) {
<div class="row loading-container">
<div class="col-2" *ngFor="let item of [1,2,3,4,5]">
<p-skeleton width="100%" height="270px"></p-skeleton>
</div>
</div>
}
</div>

View file

@ -105,30 +105,6 @@
padding: 5px;
}
.loading-container {
display: flex;
gap: 10px;
padding: 0 20px;
margin-top: 20px;
}
.loading-container .col-2 {
flex: 0 0 auto;
width: calc(20% - 8px);
}
@media (max-width: 768px) {
.loading-container .col-2 {
width: calc(50% - 5px);
}
}
@media (max-width: 480px) {
.loading-container .col-2 {
width: calc(100% - 0px);
}
}
@media (min-width:755px){
::ng-deep .p-carousel-item{
flex: 1 0 200px !important;

View file

@ -1,4 +1,4 @@
import { Component, OnInit, Input, ViewChild, OnDestroy, signal } from "@angular/core";
import { Component, OnInit, Input, ViewChild, OnDestroy } from "@angular/core";
import { IRecentlyRequested, IRequestEngineResult, RequestType } from "../../../interfaces";
import { Carousel } from 'primeng/carousel';
import { ResponsiveOptions } from "../carousel.options";
@ -31,7 +31,6 @@ export class RecentlyRequestedListComponent implements OnInit, OnDestroy {
@ViewChild('carousel', {static: false}) carousel: Carousel;
public requests$: Observable<IRecentlyRequested[]>;
public requests = signal<IRecentlyRequested[]>(null);
public responsiveOptions: any;
public RequestType = RequestType;
@ -120,13 +119,11 @@ export class RecentlyRequestedListComponent implements OnInit, OnDestroy {
}
private loadData() {
this.requestServiceV2.getRecentlyRequested().pipe(
this.requests$ = this.requestServiceV2.getRecentlyRequested().pipe(
tap(() => this.loading()),
takeUntil(this.$loadSub),
finalize(() => this.finishLoading())
).subscribe(x => {
this.requests.set(x);
});
);
}
private loading() {

View file

@ -52,7 +52,6 @@ export enum NotificationType {
IssueComment = 10,
Newsletter = 11,
PartiallyAvailable = 12,
PlexWatchlistTokenExpired = 13
}
export interface IDiscordNotifcationSettings extends INotificationSettings {

View file

@ -25,19 +25,12 @@ export interface IMovieRequests extends IFullBaseRequest {
requestedDate: Date;
watchedByRequestedUser: boolean;
playedByUsersCount: number;
requestCombination: RequestCombination;
// For the UI
rootPathOverrideTitle: string;
qualityOverrideTitle: string;
}
export enum RequestCombination {
Normal,
FourK,
Both
}
export interface IMovieAdvancedOptions {
requestId: number;
qualityOverride: number;

View file

@ -114,7 +114,6 @@ export interface IPlexSettings extends ISettings {
enable: boolean;
enableWatchlistImport: boolean;
monitorAll: boolean;
notifyOnWatchlistTokenExpiration: boolean;
servers: IPlexServer[];
}

View file

@ -1,4 +1,4 @@
<div *ngIf="landingPageSettings && customizationSettings" style="overflow: auto !important;">
<div *ngIf="landingPageSettings && customizationSettings" style="overflow:hidden">
<ombi-image-background></ombi-image-background>
<div class="small-middle-container">

View file

@ -1,11 +1,9 @@
@import "./styles/variables.scss";
@import "./styles/variables.scss";
.small-middle-container{
height:100vh;
overflow: auto; /* or overflow: auto; */
}
.row{
overflow: auto; /* or overflow: auto; */
display:flex;
align-items: center;
justify-content: center;
@ -89,4 +87,4 @@ span, b, i, p {
.logo-container{
display:flex;
justify-content: center;
}
}

View file

@ -1,6 +1,6 @@
import { Component, Inject, OnInit } from "@angular/core";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { IAdvancedData, IRadarrProfile, IRadarrRootFolder, RequestCombination } from "../../../../../interfaces";
import { IAdvancedData, IRadarrProfile, IRadarrRootFolder } from "../../../../../interfaces";
import { RadarrService } from "../../../../../services";
@Component({
@ -11,8 +11,6 @@ export class MovieAdvancedOptionsComponent implements OnInit {
public radarrProfiles: IRadarrProfile[];
public radarrRootFolders: IRadarrRootFolder[];
public show4k: boolean = false;
public showNormal: boolean = false;
constructor(public dialogRef: MatDialogRef<MovieAdvancedOptionsComponent>, @Inject(MAT_DIALOG_DATA) public data: IAdvancedData,
private radarrService: RadarrService
@ -21,31 +19,16 @@ export class MovieAdvancedOptionsComponent implements OnInit {
public async ngOnInit() {
this.show4k = this.data.movieRequest.requestCombination === RequestCombination.FourK || this.data.movieRequest.requestCombination === RequestCombination.Both;
this.showNormal = this.data.movieRequest.requestCombination === RequestCombination.Normal || this.data.movieRequest.requestCombination === RequestCombination.Both;
if (this.show4k) {
this.radarrService.getQualityProfiles4kFromSettings().subscribe(c => {
this.radarrProfiles = c;
this.data.profiles = c;
this.setQualityOverrides();
});
this.radarrService.getRootFolders4kFromSettings().subscribe(c => {
this.radarrRootFolders = c;
this.data.rootFolders = c;
this.setRootFolderOverrides();
});
} else { // Currently show either 4k or normal, if it's a dual request there needs to be more work done to save the overrides for 4k separately
this.radarrService.getQualityProfilesFromSettings().subscribe(c => {
this.radarrProfiles = c;
this.data.profiles = c;
this.setQualityOverrides();
});
this.radarrService.getRootFoldersFromSettings().subscribe(c => {
this.radarrRootFolders = c;
this.data.rootFolders = c;
this.setRootFolderOverrides();
});
}
this.radarrService.getQualityProfilesFromSettings().subscribe(c => {
this.radarrProfiles = c;
this.data.profiles = c;
this.setQualityOverrides();
});
this.radarrService.getRootFoldersFromSettings().subscribe(c => {
this.radarrRootFolders = c;
this.data.rootFolders = c;
this.setRootFolderOverrides();
});
}
private setQualityOverrides(): void {

View file

@ -1,6 +1,5 @@
import { Pipe, PipeTransform } from "@angular/core";
import { FormatPipe } from 'ngx-date-fns';
import { parseISO, format } from 'date-fns';
@Pipe({
name: "ombiDate",
@ -11,16 +10,8 @@ export class OmbiDatePipe implements PipeTransform {
private FormatPipe: FormatPipe,
) {}
public transform(value: string, formatStr: string ) {
if (!value) {
return '';
}
// Parse the ISO string as UTC
const utcDate = parseISO(value);
// Format the date using date-fns format function
// This will automatically handle the UTC to local conversion
return format(utcDate, formatStr);
public transform(value: string, format: string ) {
const date = new Date(value);
return this.FormatPipe.transform(date, format);
}
}

View file

@ -1,40 +1,38 @@
<div class="watchlist-dialog-container">
<mat-card class="watchlist-dialog-card">
<mat-card-header>
<mat-card-title>Watchlist User Errors</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="watchlist-info-section">
<mat-icon color="warn" class="info-icon">error_outline</mat-icon>
<span>
If there is an authentication error, this is because of an authentication issue with Plex (Token has expired).
If this happens the user needs to re-login to Ombi.
</span>
</div>
<div class="watchlist-legend">
<span><mat-icon color="primary">check_circle</mat-icon> Successfully syncing the watchlist</span>
<span><mat-icon color="warn">cancel</mat-icon> Authentication error syncing the watchlist</span>
<span><mat-icon color="accent">person_off</mat-icon> Not enabled for user (They need to log into Ombi via Plex)</span>
</div>
<table mat-table *ngIf="dataSource" [dataSource]="dataSource" matSort class="mat-elevation-z8 modern-table">
<ng-container matColumnDef="userName">
<th mat-header-cell *matHeaderCellDef> Username </th>
<td mat-cell *matCellDef="let element"> {{element.userName}} </td>
</ng-container>
<ng-container matColumnDef="syncStatus">
<th mat-header-cell *matHeaderCellDef> Watchlist Sync Result </th>
<td mat-cell *matCellDef="let element">
<mat-icon *ngIf="element.syncStatus === WatchlistSyncStatus.Successful" color="primary">check_circle</mat-icon>
<mat-icon *ngIf="element.syncStatus === WatchlistSyncStatus.Failed" color="warn">cancel</mat-icon>
<mat-icon *ngIf="element.syncStatus === WatchlistSyncStatus.NotEnabled" color="accent">person_off</mat-icon>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</mat-card-content>
<mat-card-actions align="end">
<button mat-stroked-button mat-dialog-close color="accent">Close</button>
</mat-card-actions>
</mat-card>
<div class="small-middle-container">
<fieldset style="fieldset">
<legend mat-dialog-title>Watchlist User Errors</legend>
<div mat-dialog-content>
<p>
If there is an authentication error, this is because of an authentication issue with Plex (Token has expired).
If this happens the user needs to re-login to Ombi.
</p>
<p>
<em class="fa-solid fa-check key"></em> Successfully syncing the watchlist
<br>
<em class="fa-solid fa-times key"></em> Authentication error syncing the watchlist
<br>
<em class="fas fa-user-alt-slash key"></em> Not enabled for user (They need to log into Ombi via Plex)
</p>
<table mat-table *ngIf="dataSource" [dataSource]="dataSource" matSort class="mat-elevation-z8">
<ng-container matColumnDef="userName">
<th mat-header-cell *matHeaderCellDef> Username </th>
<td mat-cell *matCellDef="let element"> {{element.userName}} </td>
</ng-container>
<ng-container matColumnDef="syncStatus">
<th mat-header-cell *matHeaderCellDef> Watchlist Sync Result </th>
<td mat-cell *matCellDef="let element">
<em *ngIf="element.syncStatus === WatchlistSyncStatus.Successful" class="fa-solid fa-check"></em>
<em *ngIf="element.syncStatus === WatchlistSyncStatus.Failed" class="fa-solid fa-times"></em>
<em *ngIf="element.syncStatus === WatchlistSyncStatus.NotEnabled" class="fas fa-user-alt-slash"></em>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close>Close</button>
</mat-dialog-actions>
</fieldset>
</div>

View file

@ -10,96 +10,4 @@
.key {
width: 40px;
}
.watchlist-dialog-container {
display: flex;
justify-content: center;
align-items: flex-start;
margin: 0 auto;
}
.watchlist-dialog-card {
background: #23272f;
color: #f1f3f6;
border-radius: 12px;
border: 1px solid #353a45;
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.25);
min-width: 420px;
max-width: 600px;
width: 100%;
max-height: 70vh;
display: flex;
flex-direction: column;
}
mat-card-content {
flex: 1 1 auto;
overflow-y: auto;
min-height: 0;
}
mat-card-header {
border-bottom: 1px solid #353a45;
margin-bottom: 12px;
flex: 0 0 auto;
}
mat-card-title {
color: #fff !important;
font-weight: 700 !important;
letter-spacing: 0.5px;
}
.watchlist-info-section {
display: flex;
align-items: center;
background: #23272f;
color: #e0e3ea;
padding: 12px 0 8px 0;
font-size: 15px;
gap: 12px;
}
.info-icon {
font-size: 28px;
color: #ffb300;
}
.watchlist-legend {
display: flex;
flex-direction: column;
gap: 4px;
margin-bottom: 18px;
margin-top: 8px;
font-size: 14px;
color: #b0b6c3;
}
.watchlist-legend mat-icon {
vertical-align: middle;
margin-right: 6px;
}
.modern-table {
background: transparent;
color: #f1f3f6;
border-radius: 8px;
margin-top: 10px;
}
.modern-table th, .modern-table td {
color: #f1f3f6;
font-size: 15px;
}
mat-card-actions {
padding-top: 16px;
flex: 0 0 auto;
background: #23272f;
}
button[mat-stroked-button] {
font-weight: 600;
border-radius: 6px;
}

View file

@ -1,179 +1,137 @@
<settings-menu></settings-menu>
<div class="plex-settings-container" *ngIf="settings">
<mat-card class="settings-card">
<mat-card-header>
<mat-card-title>Plex Configuration</mat-card-title>
</mat-card-header>
<mat-card-content>
<!-- Watchlist Settings Section -->
<div class="settings-section">
<div class="section-header">
<h2>Watchlist Settings</h2>
</div>
<div class="settings-grid">
<mat-card class="setting-card">
<mat-card-content>
<div class="setting-header">
<h3>Enable Plex</h3>
<mat-slide-toggle [id]="'enable'" [(ngModel)]="settings.enable"></mat-slide-toggle>
</div>
</mat-card-content>
</mat-card>
<mat-card class="setting-card">
<mat-card-content>
<div class="setting-header">
<h3>Enable User Watchlist Requests</h3>
<mat-slide-toggle [id]="'enableWatchlistImport'" [(ngModel)]="settings.enableWatchlistImport"></mat-slide-toggle>
</div>
<p class="setting-description">
When a Plex User adds something to their watchlist in Plex, it will turn up in Ombi as a Request if enabled.
This <strong>only</strong> applies to users that are logging in with their Plex Account.
<br>Request limits if set are all still applied
</p>
</mat-card-content>
</mat-card>
<mat-card class="setting-card" [class.disabled]="!settings.enableWatchlistImport">
<mat-card-content>
<div class="setting-header">
<h3>Request Whole Show</h3>
<mat-slide-toggle [id]="'monitorAll'" [(ngModel)]="settings.monitorAll" [disabled]="!settings.enableWatchlistImport"></mat-slide-toggle>
</div>
<p class="setting-description">
If enabled then watchlist requests for TV Shows will request the <strong>whole</strong> show.
If not enabled it will only request the latest season.
</p>
</mat-card-content>
</mat-card>
<mat-card class="setting-card" [class.disabled]="!settings.enableWatchlistImport">
<mat-card-content>
<div class="setting-header">
<h3>Notify on Token Expiration</h3>
<mat-slide-toggle [id]="'notifyOnWatchlistTokenExpiration'" [(ngModel)]="settings.notifyOnWatchlistTokenExpiration" [disabled]="!settings.enableWatchlistImport"></mat-slide-toggle>
</div>
<p class="setting-description">
When enabled, users will receive a notification if their Plex watchlist token expires and they need to log into Ombi again to continue using the watchlist feature.
<br><strong>Note:</strong> This requires email notifications to be configured in the notification settings, and users must have an email address set on their account to receive these notifications.
</p>
</mat-card-content>
</mat-card>
</div>
<mat-card class="info-banner">
<mat-icon color="primary" style="margin-right: 12px;">info</mat-icon>
<span style="flex:1;">
Some users may need to re-log in to use the watchlist feature.
</span>
<button mat-button color="accent" (click)="openWatchlistUserLog()">
View Users
</button>
</mat-card>
<div class="small-middle-container" *ngIf="settings">
<fieldset style="width:100%;">
<legend>Plex Configuration</legend>
<div class="col-12">
<div class="md-form-field align-right">
<button (click)="openWatchlistUserLog()" type="button" class="mat-focus-indicator mat-flat-button mat-button-base mat-accent">Watchlist User Errors</button>
</div>
<!-- Main Content Area -->
<div class="main-content">
<!-- Left Column - Servers and Actions -->
<div class="content-column">
<!-- Servers Section -->
<div class="settings-section">
<h2>Plex Servers</h2>
<div class="servers-grid">
<mat-card class="server-card" *ngFor="let server of settings.servers">
<mat-card-content>
<button mat-button (click)="edit(server)" [id]="server.name + '-button'">
<mat-icon>dns</mat-icon>
<span>{{server.name}}</span>
</button>
</mat-card-content>
</mat-card>
</div>
<settings-plex-form-field [label]="'Enable'" [type]="'checkbox'" [id]="'enable'" [(value)]="settings.enable"></settings-plex-form-field>
<mat-card class="server-card new-server">
<mat-card-content>
<button mat-button (click)="newServer()" id="newServer">
<mat-icon>add_circle</mat-icon>
<span>Add Server</span>
</button>
</mat-card-content>
</mat-card>
</div>
</div>
<settings-plex-form-field [label]="'Enable User Watchlist Requests'" [type]="'checkbox'" [id]="'enableWatchlistImport'" [(value)]="settings.enableWatchlistImport">
<small bottom>When a Plex User adds something to their watchlist in Plex, it will turn up in Ombi as a Request if enabled. This <b>only</b> applies to users that are logging in with their Plex Account
<br>Request limits if set are all still applied
</small>
</settings-plex-form-field>
<!-- Sync Actions Section -->
<div class="settings-section">
<h2>Sync Actions</h2>
<div class="sync-actions-grid">
<button mat-stroked-button (click)="runSync(PlexSyncType.Full)" id="fullSync">
<mat-icon>sync</mat-icon>
Full Sync
</button>
<button mat-stroked-button (click)="runSync(PlexSyncType.RecentlyAdded)" id="recentlyAddedSync">
<mat-icon>update</mat-icon>
Partial Sync
</button>
<button mat-stroked-button (click)="runSync(PlexSyncType.ClearAndReSync)" id="clearData">
<mat-icon>cleaning_services</mat-icon>
Clear & Resync
</button>
<button mat-stroked-button (click)="runSync(PlexSyncType.WatchlistImport)" id="watchlistImport">
<mat-icon>playlist_add</mat-icon>
Run Watchlist Import
</button>
</div>
</div>
</div>
<settings-plex-form-field [disabled]="!settings.enableWatchlistImport" [label]="'Watchlist - Request Whole Show'" disabled [type]="'checkbox'" [id]="'monitorAll'" [(value)]="settings.monitorAll">
<small bottom>If enabled then watchlist requests for TV Shows will request the <strong><em>whole</em></strong> show. If not enabled it will only request the latest season.
</small>
</settings-plex-form-field>
<!-- Right Column - Plex Credentials -->
<div class="content-column">
<div class="settings-section">
<h2>Plex Credentials</h2>
<mat-card class="credentials-card">
<mat-card-content>
<p class="credentials-description">
These fields are optional to automatically fill in your Plex server settings.
<br>This will pass your username and password to the Plex.tv API to grab the servers associated with this user.
<br>If you have 2FA enabled on your account, you need to append the 2FA code to the end of your password.
</p>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Username</mat-label>
<input matInput [id]="'username'" [(ngModel)]="username">
</mat-form-field>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Password</mat-label>
<input matInput [id]="'password'" type="password" [(ngModel)]="password">
</mat-form-field>
<hr>
<button mat-raised-button color="primary" id="loadServers" (click)="requestServers()" class="full-width">
<mat-icon>key</mat-icon>
Load Servers
</button>
<div class="row">
<div class="col-md-7">
<h2 style="margin: 1em 0 0 0;">Servers</h2>
<mat-list style="display:flex; flex-flow: wrap;">
<mat-card class="server-card" *ngFor="let server of settings.servers">
<button mat-button (click)="edit(server)" id="{{server.name}}-button">
<h3>{{server.name}}</h3>
</button>
</mat-card>
<mat-form-field appearance="outline" class="full-width mt-3">
<mat-label>Select Server</mat-label>
<mat-select [id]="'servers'" *ngIf="loadedServers">
<mat-option (click)="selectServer(s)" *ngFor="let s of loadedServers.servers.server" [value]="s.server">
{{s.name}}
</mat-option>
</mat-select>
<input matInput disabled placeholder="No Servers Loaded" *ngIf="!loadedServers">
</mat-form-field>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
</mat-card-content>
<mat-card class="server-card new-server-card">
<button mat-button (click)="newServer()" id="newServer">
<i class="fas fa-plus fa-xl"></i>
<h3>Manually Add Server</h3>
</button>
</mat-card>
</mat-list>
<mat-card-actions align="end">
<button mat-raised-button color="accent" (click)="save()" id="save">
<mat-icon>save</mat-icon>
Save Changes
<div class="row">
<br />
<div class="form-group col-2">
<button mat-raised-button (click)="runSync(PlexSyncType.Full)" type="button" id="fullSync"
class="mat-focus-indicator mat-stroked-button mat-button-base">Full
Sync</button><br />
</div>
<div class="form-group col-2">
<button mat-raised-button (click)="runSync(PlexSyncType.RecentlyAdded)" type="button" id="recentlyAddedSync"
class="mat-focus-indicator mat-stroked-button mat-button-base">Partial Sync</button>
</div>
<div class="form-group col-2">
<button mat-raised-button (click)="runSync(PlexSyncType.ClearAndReSync)" type="button" id="clearData"
class="mat-focus-indicator mat-stroked-button mat-button-base">
Clear Data And Resync
</button>
</mat-card-actions>
</mat-card>
</div>
<div class="form-group col-12">
<button mat-raised-button (click)="runSync(PlexSyncType.WatchlistImport)" type="button" id="watchlistImport"
class="mat-focus-indicator mat-stroked-button mat-button-base">
Run Watchlist Import
</button>
</div>
</div>
<div class="row">
<div class="col-md-2">
<div class="form-group">
<div>
<button mat-raised-button (click)="save()" type="submit" id="save"
class="mat-focus-indicator mat-raised-button mat-button-base mat-accent">Submit</button>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-5">
<div class="md-form-field">
<label for="username" class="control-label">
<h3>Plex Credentials</h3>
<small>These fields are optional to automatically fill in your Plex server settings. <br>
This will pass your username and password to the Plex.tv API to grab the servers associated with this user.
<br>
If you have 2FA enabled on your account, you need to append the 2FA code to the end of your password.</small>
</label>
</div>
<settings-plex-form-field [label]="'Username'" [id]="'username'" [(value)]="username"></settings-plex-form-field>
<settings-plex-form-field [label]="'Password'" [id]="'password'" [type]="'password'" [(value)]="password"></settings-plex-form-field>
<div class="md-form-field">
<div class="right">
<button mat-raised-button id="loadServers" (click)="requestServers()"
class="mat-stroked-button">Load Servers
<i class="fas fa-key"></i>
</button>
</div>
</div>
<div class="row">
<div class="col-2 align-self-center">
Please select the server:
</div>
<div class="md-form-field col-10">
<div *ngIf="!loadedServers">
<mat-form-field appearance="outline" floatLabel=auto>
<input disabled matInput placeholder="No Servers Loaded" id="servers">
</mat-form-field>
</div>
<div *ngIf="loadedServers">
<mat-form-field appearance="outline">
<mat-select placeholder="Servers Loaded! Please Select" id="servers">
<mat-option (click)="selectServer(s)"
*ngFor="let s of loadedServers.servers.server" [value]="s.server">
{{s.name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
</div>
</div>
</fieldset>
</div>
<!--(){{settings|json}}-->

View file

@ -43,258 +43,4 @@
h3 {
margin: 0;
}
}
.plex-settings-container {
padding: 20px;
max-width: 1400px;
margin: 0 auto;
}
.settings-card {
margin-bottom: 20px;
background: transparent;
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.25);
border-radius: 12px;
border: 1px solid #353a45;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.settings-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 24px;
margin-bottom: 30px;
}
.setting-card {
height: 100%;
background: transparent;
border-radius: 10px;
border: 1px solid #353a45;
box-shadow: 0 1px 6px 0 rgba(0,0,0,0.18);
color: #f1f3f6;
}
.setting-card.disabled {
opacity: 0.6;
}
.setting-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
font-weight: 600;
color: #fff;
}
.setting-description {
color: #e0e3ea;
font-size: 15px;
margin: 0;
font-weight: 400;
line-height: 1.6;
}
.main-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 36px;
margin-top: 36px;
}
.servers-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 18px;
}
.server-card {
text-align: center;
background: transparent;
border-radius: 10px;
border: 1px solid #353a45;
box-shadow: 0 1px 6px 0 rgba(0,0,0,0.18);
color: #f1f3f6;
}
.server-card button {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24px;
color: #f1f3f6;
font-weight: 500;
}
.server-card mat-icon {
font-size: 32px;
height: 32px;
width: 32px;
margin-bottom: 10px;
color: #90caf9;
}
.sync-actions-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 18px;
}
.sync-actions-grid button {
display: flex;
flex-direction: column;
align-items: center;
padding: 24px;
color: #f1f3f6;
background: transparent;
border: 1px solid #353a45;
border-radius: 10px;
font-weight: 500;
box-shadow: 0 1px 6px 0 rgba(0,0,0,0.18);
}
.sync-actions-grid mat-icon {
font-size: 32px;
height: 32px;
width: 32px;
margin-bottom: 10px;
color: #90caf9;
}
.credentials-card {
padding: 24px;
background: transparent;
border-radius: 10px;
border: 1px solid #353a45;
box-shadow: 0 1px 6px 0 rgba(0,0,0,0.18);
color: #f1f3f6;
}
.credentials-description {
color: #e0e3ea;
margin-bottom: 20px;
font-size: 15px;
font-weight: 400;
}
mat-card-title, h2, h3 {
color: #fff !important;
font-weight: 700 !important;
letter-spacing: 0.5px;
}
mat-card-header {
border-bottom: 1px solid #353a45;
margin-bottom: 16px;
}
mat-form-field {
color: #f1f3f6 !important;
}
mat-label, .mat-form-field-label {
color: #b0b6c3 !important;
font-weight: 500;
}
input[matInput], .mat-input-element {
color: #f1f3f6 !important;
background: transparent !important;
}
mat-select {
color: #f1f3f6 !important;
background: transparent !important;
}
.full-width {
width: 100%;
}
.mt-3 {
margin-top: 1rem;
}
.mat-slide-toggle.mat-checked .mat-slide-toggle-bar {
background-color: #90caf9 !important;
}
.mat-slide-toggle-thumb {
background-color: #2196f3 !important;
}
button[mat-flat-button], button[mat-raised-button], button[mat-stroked-button], button[mat-button] {
font-weight: 600;
letter-spacing: 0.2px;
color: #f1f3f6;
background: #2196f3;
border-radius: 6px;
box-shadow: 0 1px 4px 0 rgba(0,0,0,0.12);
transition: background 0.2s;
}
button[mat-flat-button]:hover, button[mat-raised-button]:hover, button[mat-stroked-button]:hover, button[mat-button]:hover {
background: #42a5f5;
}
@media (max-width: 1200px) {
.main-content {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.settings-grid {
grid-template-columns: 1fr;
}
.servers-grid {
grid-template-columns: 1fr;
}
.sync-actions-grid {
grid-template-columns: 1fr;
}
}
.watchlist-errors-btn-row {
display: flex;
justify-content: center;
margin-top: 18px;
}
.info-banner {
display: flex;
align-items: center;
background: #23272f;
color: #e0e3ea;
border: 1px solid #1976d2;
box-shadow: 0 1px 6px 0 rgba(0,0,0,0.12);
border-radius: 8px;
padding: 16px 20px;
margin-top: 18px;
margin-bottom: 0;
font-size: 16px;
font-weight: 500;
gap: 12px;
}
.info-banner mat-icon {
font-size: 28px;
color: #42a5f5;
}
.info-banner button[mat-button] {
margin-left: 16px;
font-weight: 600;
}
}

View file

@ -28,12 +28,10 @@
<mat-form-field appearance="outline" >
<mat-label>Hostname or IP</mat-label>
<input matInput formControlName="ip">
<mat-error>Please enter a valid hostname or ip address</mat-error>
</mat-form-field>
<mat-form-field appearance="outline" >
<mat-label>Port</mat-label>
<input matInput formControlName="port">
<mat-error>Please enter a valid port number</mat-error>
</mat-form-field>
<mat-slide-toggle formControlName="ssl">
SSL
@ -44,7 +42,6 @@
<mat-form-field appearance="outline" >
<mat-label>API key</mat-label>
<input matInput formControlName="apiKey">
<mat-error>Please enter an API Key</mat-error>
</mat-form-field>
</div>
<div class="md-form-field">
@ -68,7 +65,6 @@
{{quality.name}}
</mat-option>
</mat-select>
<mat-error>Please select a value</mat-error>
</mat-form-field>
</div>
@ -84,7 +80,6 @@
{{folder.path}}
</mat-option>
</mat-select>
<mat-error>Please select a value</mat-error>
</mat-form-field>
</div>
@ -100,7 +95,6 @@
{{tag.label}}
</mat-option>
</mat-select>
<mat-error>Please select a value</mat-error>
</mat-form-field>
</div>
@ -113,7 +107,6 @@
{{min.name}}
</mat-option>
</mat-select>
<mat-error>Please select a value</mat-error>
</mat-form-field>
</div>
</div>

View file

@ -63,14 +63,14 @@ export class RadarrFormComponent implements OnInit {
}
public toggleValidators() {
debugger;
const enabled = this.form.controls.enabled.value as boolean;
this.form.controls.apiKey.setValidators(enabled ? [Validators.required] : null);
this.form.controls.defaultQualityProfile.setValidators(enabled ? [Validators.required, Validators.min(1)] : null);
this.form.controls.defaultQualityProfile.setValidators(enabled ? [Validators.required] : null);
this.form.controls.defaultRootPath.setValidators(enabled ? [Validators.required] : null);
this.form.controls.ip.setValidators(enabled ? [Validators.required] : null);
this.form.controls.port.setValidators(enabled ? [Validators.required, Validators.min(1)] : null);
this.form.controls.port.setValidators(enabled ? [Validators.required] : null);
this.form.controls.minimumAvailability.setValidators(enabled ? [Validators.required] : null);
enabled ? this.form.markAllAsTouched() : this.form.markAsUntouched();
}
public getProfiles(form: UntypedFormGroup) {
@ -120,7 +120,6 @@ export class RadarrFormComponent implements OnInit {
this.notificationService.success("Successfully connected to Radarr!");
} else if (result.expectedSubDir) {
this.notificationService.error("Your Radarr Base URL must be set to " + result.expectedSubDir);
form.controls.subDir.setValue(result.expectedSubDir);
} else {
this.notificationService.error("We could not connect to Radarr!");
}

View file

@ -1,5 +1,5 @@
<settings-menu></settings-menu>
<div *ngIf="form$ | async as form" class="small-middle-container">
<div *ngIf="form" class="small-middle-container">
<fieldset>
<legend>Radarr Settings</legend>
<div class="md-form-field" style="margin-top:1em;"></div>
@ -33,4 +33,4 @@
</div>
</form>
</fieldset>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show more