diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..419d87940
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,8 @@
+# These are supported funding model platforms
+
+github: [tidusjar]
+patreon: tidusjar
+#open_collective: # Replace with a single Open Collective username
+#ko_fi: # Replace with a single Ko-fi username
+#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+custom: https://paypal.me/PlexRequestsNet
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 2684ccc3e..000000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-#### Ombi build Version:
-
-V 3.0.XX
-
-#### Update Branch:
-
-Open Beta
-
-#### Media Sever:
-
-Plex/Emby
-
-#### Media Server Version:
-
-
-
-#### Operating System:
-
-(Place text here)
-
-
-#### Ombi Applicable Logs (from `/logs/` directory or the Admin page):
-
-```
-
-(Logs go here. Don't remove the ' tags for showing your logs correctly. Please make sure you remove any personal information from the logs)
-
-```
-
-#### Problem Description:
-
-(Place text here)
-
-#### Reproduction Steps:
-
-Please include any steps to reproduce the issue, this the request that is causing the problem etc.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 000000000..2236cc395
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,37 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Logs (Logs directory where Ombi is located)**
+If applicable, a snippet of the logs that seems relevant to the bug if present.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+
+**Ombi Version (please complete the following information):**
+ - Version [e.g. 3.0.1158]
+- Media Server [e.g. Plex]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 000000000..b3deb4a73
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,23 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 60
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 7
+# Issues with these labels will never be considered stale
+exemptLabels:
+ - pinned
+ - security
+ - bug / issue
+ - help wanted
+ - possible feature
+ - planned
+ - in progress
+ - enhancement
+# Label to use when marking an issue as stale
+staleLabel: wontfix
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ recent activity. It will be closed if no further activity occurs. Thank you
+ for your contributions.
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
diff --git a/.github/workflows/aspnetcore.yml b/.github/workflows/aspnetcore.yml
new file mode 100644
index 000000000..e562216cc
--- /dev/null
+++ b/.github/workflows/aspnetcore.yml
@@ -0,0 +1,18 @@
+name: ASP.NET Core CI
+
+on: [push, pull_request]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Setup .NET Core
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: 2.2.108
+
+ - name: Build Backend
+ run: ./build.sh --settings_skipverification=true
diff --git a/.github/workflows/test.workflow b/.github/workflows/test.workflow
new file mode 100644
index 000000000..7c88813d1
--- /dev/null
+++ b/.github/workflows/test.workflow
@@ -0,0 +1,9 @@
+workflow "New workflow" {
+ on = "push"
+ resolves = [".NET Core CLI"]
+}
+
+action ".NET Core CLI" {
+ uses = "baruchiro/github-actions@0.0.1"
+ args = "build src/Ombi.sln"
+}
diff --git a/.gitignore b/.gitignore
index 771a7bacd..587f09568 100644
--- a/.gitignore
+++ b/.gitignore
@@ -243,3 +243,6 @@ _Pvt_Extensions
# CAKE - C# Make
/Tools/*
*.db-journal
+
+# Ignore local vscode config
+*.vscode
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fb91d9d96..ae8417bae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,1346 @@
### **New Features**
+- Added better support for Jellyfin, we will now auto detect if it's a jellyfin server after pressing the discover button. [tidusjar]
+
+- Update aspnetcore.yml. [Jamie]
+
+- Update aspnetcore.yml. [Jamie]
+
+- Update aspnetcore.yml. [Jamie]
+
+- Update aspnetcore.yml. [Jamie]
+
+- Update aspnetcore.yml. [Jamie]
+
+- Update and rename .github/workflows to .github/.github/workflows/test.workflow. [Jamie]
+
+- Update aspnetcore.yml. [Jamie]
+
+- Update aspnetcore.yml. [Jamie]
+
+- Update aspnetcore.yml. [Jamie]
+
+- Added a bit more logging into the recently added scan. [tidusjar]
+
+- Update emby.component.html. [sorano]
+
+- Update EmbyHelper.cs. [sorano]
+
+- Update CHANGELOG.md. [Jamie]
+
+### **Fixes**
+
+- Fixed #3078. [tidusjar]
+
+- Fixes issue #3195 The new string extension method ToHttpsUrl ensures that URLs starting with "https" are no longer turned into "httpss" The commit also replaces all occurances of the error prone .Replace("http", "https") in the whole solution. [msdeibel]
+
+- Create test.workflow. [Jamie]
+
+- Delete test.workflow. [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- Fix for #3183. [tidusjar]
+
+- Fixed an issue where running the recently added sync via the UI was running the full sync. [tidusjar]
+
+- Fixed #3143. [Jamie Rees]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- Fixed the issue when we are logging errors in the logs incorrectly. [Jamie]
+
+- Removed the lanuage profile from the Lidarr integration. [tidusjar]
+
+- Try and clear up the issue #2998. [tidusjar]
+
+- Fixed an issue where shows that have no aired, episodes are not marked as monitored in Sonarr. [tidusjar]
+
+- Fixed an error when finishing the content sync. [tidusjar]
+
+- Fixed issue where using the API to request a movie/tv show would throw an exception when only using the API Key #3091. [tidusjar]
+
+- Put "Ombi" back as the product name for Plex oAuth. [tidusjar]
+
+
+## v3.0.4680 (2019-07-17)
+
+### **New Features**
+
+- Update CHANGELOG.md. [Jamie]
+
+### **Fixes**
+
+- Fix Plex's (intentional) mistake #3073. [Jamie Rees]
+
+- #2994 Fixed the startup issue. [tidusjar]
+
+- #2994 - enable multithreading in the sql config. [Jamie Rees]
+
+
+## v3.0.4659 (2019-07-02)
+
+### **New Features**
+
+- Update appsettings.json. [Jamie]
+
+- Update CHANGELOG.md. [Jamie]
+
+
+## v3.0.4654 (2019-07-02)
+
+### **New Features**
+
+- Added further logging into the API's (debug logging) [tidusjar]
+
+- Added transactions around all of the CUD operations. [Jamie Rees]
+
+- Added some validation around the new crons. [Jamie Rees]
+
+- Added some defensive coding around when we create an artist for #2915. [tidusjar]
+
+- Update JobSetup.cs. [Jamie]
+
+- Update JobSetup.cs. [Jamie]
+
+- Added a global mutex (not used yet) and moved around the code for loggin in since I suspect the Get Roles call is using deffered execution on the database causing the lock when attempting to access straight away #2750. [Jamie Rees]
+
+- Added a lock on the database commit level to see if I can improve locked db's. [Jamie Rees]
+
+- Update dependancies. [TidusJar]
+
+- Update stale.yml. [Jamie]
+
+- Update README.md. [Dyson Parkes]
+
+- Update README.md. [Jamie]
+
+- Update README.md. [Jamie]
+
+- Update CHANGELOG.md. [Jamie]
+
+- Added stalebot. [tidusjar]
+
+### **Fixes**
+
+- Add back in the login time. [tidusjar]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (Hungarian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- New translations en.json (Bulgarian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Hungarian) [Jamie]
+
+- New translations en.json (Bulgarian) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Hungarian) [Jamie]
+
+- New translations en.json (Bulgarian) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Hungarian) [Jamie]
+
+- New translations en.json (Hungarian) [Jamie]
+
+- New translations en.json (Hungarian) [Jamie]
+
+- New translations en.json (Hungarian) [Jamie]
+
+- New translations en.json (Hungarian) [Jamie]
+
+- New translations en.json (Russian) [Jamie]
+
+- New translations en.json (Hungarian) [Jamie]
+
+- New translations en.json (Bulgarian) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- Fixed the issue where the recently added scan was actually calling the RefreshMedia which ends up wiping out the Plex cache instead of refreshing the metadata... i'm a dumbass #3023. [tidusjar]
+
+- Fix #3027. [Jamie]
+
+- Log the request. [tidusjar]
+
+- Really fixed #3010 this time. That's embarrassing. [Jamie]
+
+- Renamed "Extensions" for Spelling Mistake. [bdrumm1234]
+
+- #3010 - Make sure we only sync the Monitored Radarr movies... [tidusjar]
+
+- Fixed build. [Jamie Rees]
+
+- Fixed #2995. [Jamie Rees]
+
+- Fixed. [tidusjar]
+
+- Import System.IO. [Patrick Collins]
+
+- Add exception to handle unknown RequestType. [Patrick Collins]
+
+- Add braces to all if statements. [Patrick Collins]
+
+- Fix album-request-permission error message. [Patrick Collins]
+
+- Use string interpolation. [Austin Jackson]
+
+- Swagger index prepends configured baseurl. [Austin Jackson]
+
+- Add a internal retry when we have a locked db. [Jamie Rees]
+
+- Fixed #2374. [tidusjar]
+
+- Fixed #2950. [Jamie Rees]
+
+- Fixed #2967. [Jamie Rees]
+
+- Re-re fix the remove button. [goldenpipes]
+
+- Fixed the other error for #2955. [tidusjar]
+
+- Stuff. [tidusjar]
+
+- Logging. [tidusjar]
+
+- More to debug logging. [tidusjar]
+
+- Start the scheduler after the jobs have been assigned. [tidusjar]
+
+- Fixed some of the issues with the new scheduler not firing correctly. [Jamie Rees]
+
+- Placeholder Text for Search Boxes (#2939) [Kris Klosterman]
+
+- Reset all of the schedules due to Quartz using a different CRON system. Updated the UI code to reflect this. [tidusjar]
+
+- Fixed the scheduler! [tidusjar]
+
+- Attempting to get the new triggers working. [Jamie Rees]
+
+- Swap out the scheduler #2750. [Jamie Rees]
+
+- Moved the jobs to use quartz. [tidusjar]
+
+- Fixed the mixed content warnings and the error when removing a album request #2884. [tidusjar]
+
+- Fixed #2910. [tidusjar]
+
+- Fix for broken twitch url in readme file. [PotatoQuality]
+
+- Reverted the global app lock for the db #2750. [tidusjar]
+
+- #2750 stuff. [Jamie Rees]
+
+- More for #2750. [Jamie Rees]
+
+- Removed the auditing, was not used anyway #2750. [Jamie Rees]
+
+- Fixed #2803 in regards to the Request Button showing up. Still need to investiagte the availability side of things. [Jamie Rees]
+
+- Delete the schedules db on startup, we don't want it trying to recover the jobs. [tidusjar]
+
+- Fixed the issue where it was not picking up roles until the JWT was refreshed. [tidusjar]
+
+- Add Gotify as notification provider. [Guillaume Taquet Gasperini]
+
+- Fix cake build by setting Incubator version. [Guillaume Taquet Gasperini]
+
+- Set the View On Emby Url at runtime so the user can configure and change the URL and it will take effect straight away. [Jamie Rees]
+
+- Made use of the global mutex, this should now hopefully work #2750. [Jamie Rees]
+
+- Fixed #2636. [TidusJar]
+
+- Take out the lastlogindate update for now #2750. [tidusjar]
+
+- Fixed build. [Jamie Rees]
+
+- Fixed #2860 When a future series is unknown it should appear as available when we have the other seasons. [Jamie Rees]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- Fixed a migration issue. [tidusjar]
+
+- Set the CommandTimeout longer to see if EF can get a handle on the SQLite file when it's locked #2750. [tidusjar]
+
+- Prevented #2848 from erroring out causing further issues. [TidusJar]
+
+- Fixed #2847. [TidusJar]
+
+- Fixed a regression issue where TV Shows couldn't be requested. [TidusJar]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- Fix typo. [Jeff]
+
+- Fixed an issue where the Subscribe button was appearing on available movies. [TidusJar]
+
+- Converted the Plex Jobs to use Quartz. [Jamie]
+
+- Remove the need for the schedules.db #2994. [tidusjar]
+
+- Create FUNDING.yml. [Jamie]
+
+- Logging and slight change to the string matching now not dependant on Thread Culture #2866. [tidusjar]
+
+
+## v3.0.4256 (2019-02-19)
+
+### **New Features**
+
+- Update CHANGELOG.md. [Jamie]
+
+### **Fixes**
+
+- Fixed #2826. [tidusjar]
+
+
+## v3.0.4248 (2019-02-18)
+
+### **New Features**
+
+- Update discord link to follow the scheme of other links. [Tom McClellan]
+
+- Update issue templates. [Jamie]
+
+- Update README.md. [Jamie]
+
+- Update CHANGELOG.md. [Jamie]
+
+- Added the functionality to remove a user from getting notifications to their mobile device #2780. [tidusjar]
+
+- Added a demo mode, this will only show movies and shows that are in the public domain. Dam that stupid fruit company. [tidusjar]
+
+- Added Actor Searching for Movies! [TidusJar]
+
+- Added the ability to change where the View on Emby link goes to #2730. [TidusJar]
+
+- Added the request queue to the notifications UI so you can turn it off per notification agent #2747. [TidusJar]
+
+- Added new classes to the posters #2732. [TidusJar]
+
+### **Fixes**
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- Fix: src/Ombi/package.json to reduce vulnerabilities. [snyk-bot]
+
+- Fixed #2801 this is when a season is not correctly monitored in sonarr when approved by an admin. [tidusjar]
+
+- Small improvements to try and mitigate #2750. [tidusjar]
+
+- Removed some areas where we clear out the cache. This should help with DB locking #2750. [tidusjar]
+
+- Fixed #2810. [tidusjar]
+
+- Cannot create an issue comment with the API #2811. [tidusjar]
+
+- Set the local domain if the Application URL is set for the HELO or EHLO commands. #2636. [tidusjar]
+
+- New translations en.json (Spanish) [Jamie]
+
+- Delete ISSUE_TEMPLATE.md. [Jamie]
+
+- More minor grammatical edits. [Andrew Metzger]
+
+- Minor grammatical edits. [Andrew Metzger]
+
+- Fixed #2802 the issue where "Issues" were not being deleted correctly. [tidusjar]
+
+- Fixed #2797. [tidusjar]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- Fixed #2786. [tidusjar]
+
+- Fixed #2756. [tidusjar]
+
+- Ignore the UserName header as part of the Api is the value is an empty string. [tidusjar]
+
+- Fixed #2759. [tidusjar]
+
+- Did #2756. [TidusJar]
+
+- Fixed the exception that sometimes makes ombi fallover. [TidusJar]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- Log the error to the ui to figure out what's going on with #2755. [tidusjar]
+
+- Small fix when denying a request with a reason, we wasn't updating the ui. [TidusJar]
+
+- Make sure we can only set the ApiAlias when using the API Key. [tidusjar]
+
+- #2363 Added the ability to pass any username into the API using the ApiAlias header. [tidusjar]
+
+- Removed the Add user to Plex from Ombi. [tidusjar]
+
+
+## v3.0.4119 (2019-01-09)
+
+### **New Features**
+
+- Update CHANGELOG.md. [Jamie]
+
+- Added a page where the admin can write/style/basically do whatever they want with e.g. FAQ for the users #2715 This needs to be enabled in the Customization Settings and then it's all configured on the page. [TidusJar]
+
+- Updated the AspnetCore.App package to remove the CVE-2019-0564 vulnerability. [TidusJar]
+
+- Added a global language flag that now applies to the search by default. [tidusjar]
+
+- Updated the frontend packages (Using Angular 7 now) [TidusJar]
+
+- Added capture of anonymous analytical data. [tidusjar]
+
+- Added {AvailableDate} as a Notification Variable, this is the date the request was marked as available. See here: https://github.com/tidusjar/Ombi/wiki/Notification-Template-Variables. [tidusjar]
+
+- Added the ability to search movies via the movie db with a different language! [tidusjar]
+
+- Added the ability to specify a year when searching for movies. [tidusjar]
+
+- Update NewsletterTemplate.html. [d1slact0r]
+
+- Update NewsletterTemplate.html. [d1slact0r]
+
+- Update NewsletterTemplate.html. [d1slact0r]
+
+- Update HtmlTemplateGenerator.cs. [d1slact0r]
+
+- Update NewsletterTemplate.html. [d1slact0r]
+
+- Update HtmlTemplateGenerator.cs. [d1slact0r]
+
+- Update NewsletterTemplate.html. [d1slact0r]
+
+- Update NewsletterTemplate.html. [d1slact0r]
+
+- Update NewsletterTemplate.html. [d1slact0r]
+
+- Update HtmlTemplateGenerator.cs. [d1slact0r]
+
+- Updated boostrap #2694. [Jamie]
+
+- Added the ability to deny a request with a reason. [TidusJar]
+
+- Update EmbyEpisodeSync.cs. [Jamie]
+
+- Updated to .net core 2.2 and included a linux-arm64 build. [TidusJar]
+
+### **Fixes**
+
+- There is now a new Job in ombi that will clear out the Plex/Emby data and recache. This will prevent the issues going forward that we have when Ombi and the Media server fall out of sync with deletions/updates #2641 #2362 #1566. [TidusJar]
+
+- Potentially fix #2726. [TidusJar]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- Fixed #2725 and #2721. [TidusJar]
+
+- Made the newsletter use the default lanuage code set in the Ombi settings for movie information. [TidusJar]
+
+- Save the language code against the request so we can use it later e.g. Sending to the DVR apps. [tidusjar]
+
+- Fixed #2716. [tidusjar]
+
+- Make the newsletter BCC the users rather than creating a million newsletters (Hopefully will stop SMTP providers from marking as spam). This does mean that the custom user customization in the newsletter will no longer work. [TidusJar]
+
+- If we don't know the Plex agent, then see if it's a ImdbId, if it's not check the string for any episode and season hints #2695. [tidusjar]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- Made the search results the language specified in the search refinement. [tidusjar]
+
+- Fixed #2704. [tidusjar]
+
+- Now it is fixed :) [d1slact0r]
+
+- Android please be nice now. [d1slact0r]
+
+- Fixed title bit better. [d1slact0r]
+
+- Fixed titles. [d1slact0r]
+
+- This should fix the build for sure (stupid quotes) [d1slact0r]
+
+- Fixes build. [d1slact0r]
+
+- Rewritten the whole newsletter template. [d1slact0r]
+
+- Fixed #2697. [tidusjar]
+
+- Add linux-arm runtime identifier. [aptalca]
+
+- Add back arm packages. [aptalca]
+
+- Add arm32 package. [aptalca]
+
+- Fixed #2691. [tidusjar]
+
+- Fixed linting. [TidusJar]
+
+- Fixed the Plex OAuth when going through the wizard. [TidusJar]
+
+- Fixed #2678. [TidusJar]
+
+- Deny reason for movie requests. [TidusJar]
+
+- Set the landing and login pages background refresh to 15 seconds rather than 10 and 7. [TidusJar]
+
+- Fixed a bug with us thinking future dated emby episodes are not available, Consoldated the emby and plex search rules (since they have the same logic) [TidusJar]
+
+- Fixed build. [TidusJar]
+
+
+## v3.0.4036 (2018-12-11)
+
+### **New Features**
+
+- Changelog. [Jamie]
+
+- Added Sonarr v3 #2359. [TidusJar]
+
+### **Fixes**
+
+- !changelog. [Jamie]
+
+- Fixed a missing translation. [Jamie]
+
+- Fixed a potential security vulnerability. [Jamie]
+
+- Sorted out some of the settings pages, trying to make it consistent. [Jamie]
+
+- #2669 Fixed missing translations. [TidusJar]
+
+- Maps alias email variable for welcome emails. [Victor Usoltsev]
+
+- Increased the logo size on the landing page to match the container below it. [Jamie]
+
+- Think the request queue is done! [Jamie]
+
+- Finished off the job. [TidusJar]
+
+
+## v3.0.3988 (2018-11-23)
+
+### **New Features**
+
+- Updated the emby api since we no longer need the extra parameters to send to emby to log in a local user #2546. [Jamie]
+
+- Added the ability to get the ombi user via a Plex Token #2591. [Jamie]
+
+- Update CHANGELOG.md. [Jamie]
+
+### **Fixes**
+
+- !changelog. [Jamie]
+
+- Made the subscribe/unsubscribe button more obvious on the UI #2309. [Jamie]
+
+- Fixed #2603. [Jamie]
+
+- Fixed the issue with the user overrides #2646. [Jamie]
+
+- Fixed the issue where we could sometimes allow the request of a whole series when the user shouldn't be able to. [Jamie]
+
+- Fixed the issue where we were marking episodes as available with the Emby connection when they have not yet aired #2417 #2623. [TidusJar]
+
+- Fixed the issue where we were marking the whole season as wanted in Sonarr rather than the individual episode #2629. [TidusJar]
+
+- Fixed #2623. [Jamie]
+
+- Fixed #2633. [TidusJar]
+
+- Fixed #2639. [Jamie]
+
+- Show the TV show as available when we have all the episodes but future episodes have not aired. #2585. [Jamie]
+
+
+## v3.0.3945 (2018-10-25)
+
+### **New Features**
+
+- Update Readme for Lidarr. [Qstick]
+
+- Update CHANGELOG.md. [Jamie]
+
+### **Fixes**
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- Fixed the issue with mobile notifications. [Jamie]
+
+- Fixed #2514. [Jamie]
+
+
+## v3.0.3923 (2018-10-19)
+
+### **New Features**
+
+- Update CHANGELOG.md. [Jamie]
+
+### **Fixes**
+
+- Fixed #2601. [Jamie]
+
+
+## v3.0.3919 (2018-10-17)
+
+### **New Features**
+
+- Added automation tests for the voting feature. [TidusJar]
+
+- Update LidarrAvailabilityChecker.cs. [Jamie]
+
+- Update CHANGELOG.md. [Jamie]
+
+- Changes language selector to always show native language name. [Victor Usoltsev]
+
+- Updated test dependancies. [TidusJar]
+
+- Added in the external repo so we can rip out external stuff. [TidusJar]
+
+- Added the ability to purge/remove issues. [TidusJar]
+
+### **Fixes**
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- When a users requests content and the voting is enabled, the user who requested is an automatic +1 vote. [TidusJar]
+
+- Revert, no idea how this happened. [TidusJar]
+
+- Fixed the build. Thanks Matt! [TidusJar]
+
+- Fixes untickable mass email checkboxes in Safari. [Victor Usoltsev]
+
+- [ImgBot] optimizes images. [ImgBotApp]
+
+- Revert "Feature/purge issues" [Jamie]
+
+- Fixed the issue where user preferences was not being inported into some notifications. [TidusJar]
+
+- New role to enable users to remove their own requests. [Anojh]
+
+- Users can now remove their own requests. [Anojh]
+
+- New translations en.json (Danish) [Jamie]
+
+- Fixed lidarr newsletter bug. [Jamie]
+
+- Potentially fix the user profiles issue. [Jamie]
+
+- Hides Radarr options on movie requests page if only 1 option available. [Victor Usoltsev]
+
+- Hides Sonarr options on tv requests page if only 1 option available. [Victor Usoltsev]
+
+- Fixed the issue where we could not delete users #2558. [TidusJar]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- Subscribe the user to the request when they vote on it. [TidusJar]
+
+- Fixed #2555. [Jamie]
+
+- Fixed #2549. [Jamie]
+
+- Removed the pinID from the OAuth url #2548. [Jamie]
+
+- Put the issue purge limit on the issues page. [Jamie]
+
+- Date and times are now in the local users date time. [TidusJar]
+
+- Fixed the migration. [TidusJar]
+
+- ExternalContext migrations. [TidusJar]
+
+- The settings have now been split out of the main db. [TidusJar]
+
+- Search for the Lidarr Album when it's a new artist. [TidusJar]
+
+- The album in Lidarr does not need to be marked as monitored for us to pick up it's available. Fixes #2536. [Jamie]
+
+- Truncate the request title. [Jamie]
+
+- Fixed #2535. [Jamie]
+
+
+## v3.0.3795 (2018-09-23)
+
+### **New Features**
+
+- Update CHANGELOG.md. [Jamie]
+
+### **Fixes**
+
+- Fixed the issue with notifications not sending. [Jamie]
+
+- Removes Legacy command result variables. [Qstick]
+
+
+## v3.0.3786 (2018-09-22)
+
+### **New Features**
+
+- Update CHANGELOG.md. [Jamie]
+
+### **Fixes**
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- Fix #2529 - Change data type to long. [Anojh]
+
+- Fix #2527 - Music request not triggering search and failing. [Anojh]
+
+
+## v3.0.3776 (2018-09-21)
+
+### **New Features**
+
+- Update settingsmenu.component.html. [Jamie]
+
+- Added the request limits in the ui for music. [Jamie]
+
+- Added the root folders and qualities per user! [Jamie]
+
+- Updated all the MS packages. [TidusJar]
+
+- Update the .net core packages to fix "CVE-2018-8409: ASP.NET Core Denial Of Service Vulnerability" [TidusJar]
+
+- Change way remainingrequests component is notified. [Kenton Royal]
+
+- Added the music request limits. [TidusJar]
+
+- Added the Notification Preferences to the user. [TidusJar]
+
+- Added the API to add user notification preferences. [TidusJar]
+
+- Added more logging into the updater. [Jamie]
+
+- Update CHANGELOG.md. [Jamie]
+
+### **Fixes**
+
+- Fixed #2518. [TidusJar]
+
+- Fixed #2522. [TidusJar]
+
+- Fixed #2485. [TidusJar]
+
+- Fixed #2516. [TidusJar]
+
+- Fix bug in which requested TV wasn't logging for some users. [Kenton Royal]
+
+- Add to translations. [Kenton Royal]
+
+- Add html for displaying remaining requests on users page. [Kenton Royal]
+
+- Add quota fields to user view model. [Kenton Royal]
+
+- Users can now see the music search tab #2493. [TidusJar]
+
+- Add href to a tags so that a pointer cursor shows on requests page. [Stephen Panzer]
+
+- Allow Lidarr to specify if we should search for the album. [TidusJar]
+
+- Fixed the issue if in Radarr we only want to add and monitor, if the movie already exists we search for it. [TidusJar]
+
+- Fix bug causing wrong time to be displayed for next request. [Kenton Royal]
+
+- Bodge fix test to prevent compile error. [Kenton Royal]
+
+- Fix displaying year in issue dialog. [Stephen Panzer]
+
+- Add clearfix class. Closes #2486. [Stephen Panzer]
+
+- Correct path of lidarr component import for unix systems. [Kenton Royal]
+
+- Refactor code. [Kenton Royal]
+
+- Fix formatting error. [Kenton Royal]
+
+- Revert "Revert request.service.ts to version on upstream/develop" [Kenton Royal]
+
+- Revert request.service.ts to version on upstream/develop. [Kenton Royal]
+
+- Fix lint errors. [Kenton Royal]
+
+- Move logic for notifying when reuqest is complete. [Kenton Royal]
+
+- Remove import. [Kenton Royal]
+
+- Remove unused module. [Kenton Royal]
+
+- Refactor code. [Kenton Royal]
+
+- Add text to translation file. [Kenton Royal]
+
+- Fix query for fetching requested tv shows. [Kenton Royal]
+
+- Add vscode to gitignore. [Kenton Royal]
+
+- Fix lint errors. [Kenton Royal]
+
+- Remove unused methods from SearchController. [Kenton Royal]
+
+- Remove local vscode files. [Kenton Royal]
+
+- Fix bug when submitting requests for multiple episodes accross multiple seasons. [Kenton Royal]
+
+- Fix bug with TV requests in which requesting a seasion would treat request as single episode. [Kenton Royal]
+
+- Fix issues with remaining count updating. [Kenton Royal]
+
+- Trigger update of request limit on new request. [Kenton Royal]
+
+- Add logic for movie request count. [Kenton Royal]
+
+- Add logic for retriving request information. [Kenton Royal]
+
+- Move to seperate component and display for both TV and movies. [Kenton Royal]
+
+- Add dummy for request counter. [Kenton Royal]
+
+- Fix scss import for unix systems. [Kenton Royal]
+
+- Add methods to interface and add model class. [Kenton Royal]
+
+- !fixed lint. [TidusJar]
+
+- Fixed #2481. [TidusJar]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- Fixed #2475. [Jamie]
+
+- Stript out certain characters when sending a pushover message #2385. [TidusJar]
+
+- Add default values for Priority and Sound. [David Pooley]
+
+- Allow for the ability to set Pushover notification sound and priority from within Ombi. [David Pooley]
+
+- It works now when we request an album when we do not have the artist in Lidarr. Waiting on https://github.com/lidarr/Lidarr/issues/459 to do when we have the artist. [Jamie]
+
+- Fix non-Windows builds. Fixes #2453. [Joe Groocock]
+
+
+## v3.0.3587 (2018-08-19)
+
+### **New Features**
+
+- Added the ability to invite Plex Friends from the user management screen. [Jamie]
+
+- Added rich notifications for mobile. [Jamie]
+
+- Updater fixes. [Jamie]
+
+- Added updater test mode. [Jamie Rees]
+
+- Added a new API method to delete issue comments. [TidusJar]
+
+- Updated @ngu/carousel to beta version to remove rxjs-compat dependency. [Matt Jeanes]
+
+- Update to Angular 6/Webpack 4. [Matt Jeanes]
+
+- Update CHANGELOG.md. [Jamie]
+
+- Updated the way we create the wizard user, errors show now be fed back to the user. [Jamie]
+
+- Added Brazillian Portuguese as a language and also Polish. [Jamie]
+
+- Updated swagger. [Jamie]
+
+- Updated to 2.1.1. [Jamie]
+
+### **Fixes**
+
+- Now include the release year in the issue title #2381. [TidusJar]
+
+- Made the OAuth a Popout to work with Org. [Jamie]
+
+- Fixed #2418. [TidusJar]
+
+- #2408 Added the feature to delete comments on issues. [Jamie]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- Fixed #2440. [TidusJar]
+
+- Delete cake.config. [Chris Pritchard]
+
+- Initial attempt at getting anime seriestype working. [Chris Pritchard]
+
+- Add cake.config. [Chris Pritchard]
+
+- Fixed the issue where we wouldn't correctly mark some shows as available when there was no provider id #2429. [Jamie]
+
+- Fixed the 'loop' in the cacher #2429. [Jamie]
+
+- Fixed #2427. [Jamie]
+
+- Fixed #2424. [Jamie]
+
+- Fixed #2409. [Jamie]
+
+- More updater. [Jamie]
+
+- Humanize the request type enum in notifications e.g. TvShow will now appear as "Tv Show" #2416. [TidusJar]
+
+- Made the quality override and root folder override load when we load the show (It will now appear) [Jamie]
+
+- Fixed #2415 where power users could not set the Sonarr Quality Override or Root Folder Override. [Jamie]
+
+- #2371 Fixed the issue where certain actions would not setup the series correctly in Sonarr. [Jamie]
+
+- Tightened up the security from an API perspecitve. [TidusJar]
+
+- Stop the root folder and profile calls from erroring. [TidusJar]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- Fixed all linting. [TidusJar]
+
+- Comment out envparam stuff. [Matt Jeanes]
+
+- Fixed prod build issue. [Matt Jeanes]
+
+- Missed a tiny bit. [Matt Jeanes]
+
+- Fix test. [Matt Jeanes]
+
+- Fix test build. [Matt Jeanes]
+
+- Linting + remove debug. [Matt Jeanes]
+
+- Switch to Yarn and disable auto publish in release mode. [Matt Jeanes]
+
+- Fix for #2409. [TidusJar]
+
+- New translations en.json (Swedish) [Jamie]
+
+- New translations en.json (Spanish) [Jamie]
+
+- New translations en.json (Portuguese, Brazilian) [Jamie]
+
+- New translations en.json (Polish) [Jamie]
+
+- New translations en.json (Norwegian) [Jamie]
+
+- New translations en.json (Italian) [Jamie]
+
+- New translations en.json (German) [Jamie]
+
+- New translations en.json (French) [Jamie]
+
+- New translations en.json (Dutch) [Jamie]
+
+- New translations en.json (Danish) [Jamie]
+
+- Possible fix for #2298. [D34DC3N73R]
+
+- Fixed the text for #2370. [Jamie]
+
+- Fixed where you couldn't bulk edit the limits to 0 #2318. [Jamie]
+
+- Upgraded to .net 2.1.2 (Includes security fixes) [Jamie]
+
+
+## v3.0.3477 (2018-07-18)
+
+### **New Features**
+
- Updated the Emby availability checker to bring it more in line with what we do with Plex. [TidusJar]
- Added the ability to impersonate a user when using the API Key. This allows people to use the API and request as a certain user. #2363. [Jamie Rees]
diff --git a/README.md b/README.md
index cfc0ad23c..e8e269e7f 100644
--- a/README.md
+++ b/README.md
@@ -9,11 +9,19 @@ ____
[](https://patreon.com/tidusjar/Ombi)
[](https://paypal.me/PlexRequestsNet)
+___
+
+[](https://twitter.com/intent/follow?screen_name=tidusjar)
+
+Follow me developing Ombi!
+
+[](https://www.twitch.tv/tidusjar)
+
+
___
-
-
-
+
+_**Note:** There is no longer an iOS app due to complications outside of our control._
___
@@ -32,8 +40,9 @@ ___
# Features
Here are some of the features Ombi V3 has:
* Now working without crashes on Linux.
-* Lets users request Movies and TV Shows (whether it being the entire series, an entire season, or even single episodes.)
+* Lets users request Movies, Music, and TV Shows (whether it being the entire series, an entire season, or even single episodes.)
* Easily manage your requests
+* Allows you to set specific users to automatically have requests approved and added to the relevant service (Sonarr/Radarr/Lidarr/Couchpotato etc)
* User management system (supports plex.tv, Emby and local accounts)
* A landing page that will give you the availability of your Plex/Emby server and also add custom notification text to inform your users of downtime.
* Allows your users to get custom notifications!
@@ -41,7 +50,7 @@ Here are some of the features Ombi V3 has:
* Will show if the request is already on plex or even if it's already monitored.
* Automatically updates the status of requests when they are available on Plex/Emby
* Slick, responsive and mobile friendly UI
-* Ombi will automatically update itself :)
+* Ombi will automatically update itself :) (YMMV)
* Very fast!
### Integration
@@ -50,6 +59,7 @@ We integrate with the following applications:
* Emby
* Sonarr
* Radarr
+* Lidarr
* DogNzb
* Couch Potato
@@ -58,6 +68,7 @@ We integrate with the following applications:
Supported notifications:
* SMTP Notifications (Email)
* Discord
+* Gotify
* Slack
* Pushbullet
* Pushover
@@ -87,6 +98,7 @@ We are planning to bring back these features in V3 but for now you can find a li
| DogNzb | Yes | No |
| Issues | Yes | Yes |
| Headphones | No | Yes |
+| Lidarr | Yes | No |
# Feature Requests
Feature requests are handled on FeatHub.
@@ -115,13 +127,12 @@ Please feel free to submit a pull request!
# Donation
If you feel like donating you can donate with the below buttons!
-[](https://patreon.com/tidusjar/Ombi)
-[](https://paypal.me/PlexRequestsNet)
+
+[](https://patreon.com/tidusjar/Ombi)
+[](https://paypal.me/PlexRequestsNet)
### A massive thanks to everyone for all their help!
-## Stats
-[](https://waffle.io/tidusjar/PlexRequests.Net/metrics/throughput)
### Sponsors ###
- [JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools
diff --git a/appveyor.yml b/appveyor.yml
index 862993a21..3c60a0006 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -3,34 +3,46 @@ configuration: Release
os: Visual Studio 2017
environment:
nodejs_version: "9.8.0"
+ typescript_version: "3.0.1"
+ github_auth_token:
+ secure: H/7uCrjmWHGJxgN3l9fbhhdVjvvWI8VVF4ZzQqeXuJwAf+PgSNBdxv4SS+rMQ+RH
+ sonarrcloudtoken:
+ secure: WGkIog4wuMSx1q5vmSOgIBXMtI/leMpLbZhi9MJnJdBBuDfcv12zwXg3LQwY0WbE
install:
# Get the latest stable version of Node.js or io.js
- ps: Install-Product node $env:nodejs_version
+
+ - cmd: set path=%programfiles(x86)%\\Microsoft SDKs\TypeScript\3.0;%path%
+ - cmd: tsc -v
build_script:
+ # - dotnet tool install --global dotnet-sonarscanner
+ #- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { dotnet sonarscanner begin /k:"tidusjar_Ombi" /d:sonar.organization="tidusjar-github" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.login="$env.sonarrcloud_token" /d:sonar.analysis.mode="preview" /d:sonar.github.pullRequest="$env:APPVEYOR_PULL_REQUEST_NUMBER" /d:sonar.github.repository="https://github.com/tidusjar/ombi" /d:sonar.github.oauth="$env.github_auth_token" }
+ # - ps: if (-Not $env:APPVEYOR_PULL_REQUEST_NUMBER) { dotnet sonarscanner begin /k:"tidusjar_Ombi" /d:sonar.organization="tidusjar-github" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.login="$env.SONARRCLOUDTOKEN" }
- ps: ./build.ps1 --settings_skipverification=true
+ # - dotnet sonarscanner end /d:sonar.login="%sonarrcloudtoken%"
test: off
-
+
after_build:
- cmd: >-
- appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\windows.zip"
+ appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\windows.zip"
- appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\osx.tar.gz"
+ appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\osx.tar.gz"
- appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\linux.tar.gz"
+ appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\linux.tar.gz"
+
+
+ appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\linux-arm.tar.gz"
+
+
+ appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\windows-32bit.zip"
- appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\linux-arm.tar.gz"
-
-
- appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.1\windows-32bit.zip"
-
-
-# appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.0\linux-arm64.tar.gz"
+ appveyor PushArtifact "%APPVEYOR_BUILD_FOLDER%\src\Ombi\bin\Release\netcoreapp2.2\linux-arm64.tar.gz"
diff --git a/assets/music-placeholder.psd b/assets/music-placeholder.psd
new file mode 100644
index 000000000..5715f850a
Binary files /dev/null and b/assets/music-placeholder.psd differ
diff --git a/build.cake b/build.cake
index d200eac98..b2ae8842c 100644
--- a/build.cake
+++ b/build.cake
@@ -1,10 +1,10 @@
#tool "nuget:?package=GitVersion.CommandLine"
#addin "Cake.Gulp"
-#addin "nuget:?package=Cake.Npm&version=0.13.0"
#addin "SharpZipLib"
#addin nuget:?package=Cake.Compression&version=0.1.4
-#addin "Cake.Incubator"
+#addin "Cake.Incubator&version=3.1.0"
+#addin "Cake.Yarn"
//////////////////////////////////////////////////////////////////////
// ARGUMENTS
@@ -26,7 +26,7 @@ var csProj = "./src/Ombi/Ombi.csproj"; // Path to the project.csproj
var solutionFile = "Ombi.sln"; // Solution file if needed
GitVersion versionInfo = null;
-var frameworkVer = "netcoreapp2.1";
+var frameworkVer = "netcoreapp2.2";
var buildSettings = new DotNetCoreBuildSettings
{
@@ -81,9 +81,9 @@ Task("SetVersionInfo")
versionInfo = GitVersion(settings);
- Information("GitResults -> {0}", versionInfo.Dump());
+// Information("GitResults -> {0}", versionInfo.Dump());
- Information(@"Build:{0}",AppVeyor.Environment.Build.Dump());
+//Information(@"Build:{0}",AppVeyor.Environment.Build.Dump());
var buildVersion = string.Empty;
if(string.IsNullOrEmpty(AppVeyor.Environment.Build.Version))
@@ -122,36 +122,19 @@ Task("SetVersionInfo")
Task("NPM")
.Does(() => {
- var settings = new NpmInstallSettings {
- LogLevel = NpmLogLevel.Silent,
- WorkingDirectory = webProjDir,
- Production = true
- };
-
- NpmInstall(settings);
+ Yarn.FromPath(webProjDir).Install();
});
Task("Gulp Publish")
.IsDependentOn("NPM")
- .Does(() => {
-
- var runScriptSettings = new NpmRunScriptSettings {
- ScriptName="publish",
- WorkingDirectory = webProjDir,
- };
-
- NpmRunScript(runScriptSettings);
+ .Does(() => {
+ Yarn.FromPath(webProjDir).RunScript("publish");
});
Task("TSLint")
.Does(() =>
{
- var settings = new NpmRunScriptSettings {
- WorkingDirectory = webProjDir,
- ScriptName = "lint"
- };
-
- NpmRunScript(settings);
+ Yarn.FromPath(webProjDir).RunScript("lint");
});
Task("PrePublish")
@@ -168,7 +151,7 @@ Task("Package")
GZipCompress(osxArtifactsFolder, artifactsFolder + "osx.tar.gz");
GZipCompress(linuxArtifactsFolder, artifactsFolder + "linux.tar.gz");
GZipCompress(linuxArmArtifactsFolder, artifactsFolder + "linux-arm.tar.gz");
- //GZipCompress(linuxArm64BitArtifactsFolder, artifactsFolder + "linux-arm64.tar.gz");
+ GZipCompress(linuxArm64BitArtifactsFolder, artifactsFolder + "linux-arm64.tar.gz");
});
Task("Publish")
@@ -178,7 +161,7 @@ Task("Publish")
.IsDependentOn("Publish-OSX")
.IsDependentOn("Publish-Linux")
.IsDependentOn("Publish-Linux-ARM")
- //.IsDependentOn("Publish-Linux-ARM-64Bit")
+ .IsDependentOn("Publish-Linux-ARM-64Bit")
.IsDependentOn("Package");
Task("Publish-Windows")
@@ -189,6 +172,8 @@ Task("Publish-Windows")
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
CopyFile(buildDir + "/"+frameworkVer+"/win10-x64/Swagger.xml", buildDir + "/"+frameworkVer+"/win10-x64/published/Swagger.xml");
+
+ publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/win10-x64/published/updater");
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
});
@@ -200,6 +185,9 @@ Task("Publish-Windows-32bit")
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
CopyFile(buildDir + "/"+frameworkVer+"/win10-x86/Swagger.xml", buildDir + "/"+frameworkVer+"/win10-x86/published/Swagger.xml");
+
+
+ publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/win10-x86/published/updater");
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
});
@@ -211,6 +199,8 @@ Task("Publish-OSX")
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
CopyFile(buildDir + "/"+frameworkVer+"/osx-x64/Swagger.xml", buildDir + "/"+frameworkVer+"/osx-x64/published/Swagger.xml");
+
+ publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/osx-x64/published/updater");
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
});
@@ -222,6 +212,8 @@ Task("Publish-Linux")
DotNetCorePublish("./src/Ombi/Ombi.csproj", publishSettings);
CopyFile(buildDir + "/"+frameworkVer+"/linux-x64/Swagger.xml", buildDir + "/"+frameworkVer+"/linux-x64/published/Swagger.xml");
+
+ publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/linux-x64/published/updater");
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
});
@@ -235,6 +227,8 @@ Task("Publish-Linux-ARM")
CopyFile(
buildDir + "/"+frameworkVer+"/linux-arm/Swagger.xml",
buildDir + "/"+frameworkVer+"/linux-arm/published/Swagger.xml");
+
+ publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/linux-arm/published/updater");
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
});
@@ -248,6 +242,8 @@ Task("Publish-Linux-ARM-64Bit")
CopyFile(
buildDir + "/"+frameworkVer+"/linux-arm64/Swagger.xml",
buildDir + "/"+frameworkVer+"/linux-arm64/published/Swagger.xml");
+
+ publishSettings.OutputDirectory = Directory(buildDir) + Directory(frameworkVer +"/linux-arm64/published/updater");
DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings);
});
diff --git a/src/Ombi.Api.Emby/EmbyApi.cs b/src/Ombi.Api.Emby/EmbyApi.cs
index fcb989094..7cb702fbc 100644
--- a/src/Ombi.Api.Emby/EmbyApi.cs
+++ b/src/Ombi.Api.Emby/EmbyApi.cs
@@ -46,6 +46,17 @@ namespace Ombi.Api.Emby
return obj;
}
+ public async Task GetPublicInformation(string baseUrl)
+ {
+ var request = new Request("emby/System/Info/public", baseUrl, HttpMethod.Get);
+
+ AddHeaders(request, string.Empty);
+
+ var obj = await Api.Request(request);
+
+ return obj;
+ }
+
public async Task LogIn(string username, string password, string apiKey, string baseUri)
{
var request = new Request("emby/users/authenticatebyname", baseUri, HttpMethod.Post);
@@ -53,8 +64,6 @@ namespace Ombi.Api.Emby
{
username,
pw = password,
- password = password.GetSha1Hash().ToLower(),
- passwordMd5 = password.CalcuateMd5Hash()
};
request.AddJsonBody(body);
@@ -98,7 +107,7 @@ namespace Ombi.Api.Emby
request.AddQueryString("Fields", "ProviderIds,Overview");
- request.AddQueryString("VirtualItem", "False");
+ request.AddQueryString("IsVirtualItem", "False");
return await Api.Request>(request);
}
@@ -126,6 +135,7 @@ namespace Ombi.Api.Emby
{
return await GetInformation(mediaId, apiKey, userId, baseUrl);
}
+
public async Task GetEpisodeInformation(string mediaId, string apiKey, string userId, string baseUrl)
{
return await GetInformation(mediaId, apiKey, userId, baseUrl);
@@ -149,7 +159,7 @@ namespace Ombi.Api.Emby
request.AddQueryString("IncludeItemTypes", type);
request.AddQueryString("Fields", includeOverview ? "ProviderIds,Overview" : "ProviderIds");
- request.AddQueryString("VirtualItem", "False");
+ request.AddQueryString("IsVirtualItem", "False");
AddHeaders(request, apiKey);
@@ -167,7 +177,7 @@ namespace Ombi.Api.Emby
request.AddQueryString("startIndex", startIndex.ToString());
request.AddQueryString("limit", count.ToString());
- request.AddQueryString("VirtualItem", "False");
+ request.AddQueryString("IsVirtualItem", "False");
AddHeaders(request, apiKey);
diff --git a/src/Ombi.Api.Emby/IEmbyApi.cs b/src/Ombi.Api.Emby/IEmbyApi.cs
index b4641ea5f..3c29878b7 100644
--- a/src/Ombi.Api.Emby/IEmbyApi.cs
+++ b/src/Ombi.Api.Emby/IEmbyApi.cs
@@ -29,5 +29,6 @@ namespace Ombi.Api.Emby
Task GetSeriesInformation(string mediaId, string apiKey, string userId, string baseUrl);
Task GetMovieInformation(string mediaId, string apiKey, string userId, string baseUrl);
Task GetEpisodeInformation(string mediaId, string apiKey, string userId, string baseUrl);
+ Task GetPublicInformation(string baseUrl);
}
}
\ No newline at end of file
diff --git a/src/Ombi.Api.Emby/Models/Media/Tv/EmbyEpisodes.cs b/src/Ombi.Api.Emby/Models/Media/Tv/EmbyEpisodes.cs
index d76915923..83d64ed15 100644
--- a/src/Ombi.Api.Emby/Models/Media/Tv/EmbyEpisodes.cs
+++ b/src/Ombi.Api.Emby/Models/Media/Tv/EmbyEpisodes.cs
@@ -16,6 +16,7 @@ namespace Ombi.Api.Emby.Models.Media.Tv
public int ProductionYear { get; set; }
public bool IsPlaceHolder { get; set; }
public int IndexNumber { get; set; }
+ public int? IndexNumberEnd { get; set; }
public int ParentIndexNumber { get; set; }
public bool IsHD { get; set; }
public bool IsFolder { get; set; }
diff --git a/src/Ombi.Api.Emby/Models/PublicInfo.cs b/src/Ombi.Api.Emby/Models/PublicInfo.cs
new file mode 100644
index 000000000..01432d3c5
--- /dev/null
+++ b/src/Ombi.Api.Emby/Models/PublicInfo.cs
@@ -0,0 +1,19 @@
+namespace Ombi.Api.Emby.Models
+{
+ public class PublicInfo
+ {
+ public string LocalAddress { get; set; }
+ public string ServerName { get; set; }
+ public string Version { get; set; }
+ ///
+ /// Only populated for Jellyfin
+ ///
+ public string ProductName { get; set; }
+
+ public bool IsJellyfin => !string.IsNullOrEmpty(ProductName) && ProductName.Contains("Jellyfin");
+
+ public string OperatingSystem { get; set; }
+ public string Id { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Github/GithubApi.cs b/src/Ombi.Api.Github/GithubApi.cs
index f7b3fbcbf..6865b33fe 100644
--- a/src/Ombi.Api.Github/GithubApi.cs
+++ b/src/Ombi.Api.Github/GithubApi.cs
@@ -24,16 +24,5 @@ namespace Ombi.Api.Github
request.AddHeader("User-Agent", "Ombi");
return await _api.Request>(request);
}
-
- public async Task GetThemesRawContent(string url)
- {
- var sections = url.Split('/');
- var lastPart = sections.Last();
- url = url.Replace(lastPart, string.Empty);
- var request = new Request(lastPart, url, HttpMethod.Get);
- request.AddHeader("Accept", "application/vnd.github.v3+json");
- request.AddHeader("User-Agent", "Ombi");
- return await _api.RequestContent(request);
- }
}
}
diff --git a/src/Ombi.Api.Github/IGithubApi.cs b/src/Ombi.Api.Github/IGithubApi.cs
index 307158b72..1cca37f02 100644
--- a/src/Ombi.Api.Github/IGithubApi.cs
+++ b/src/Ombi.Api.Github/IGithubApi.cs
@@ -7,6 +7,5 @@ namespace Ombi.Api.Github
public interface IGithubApi
{
Task> GetCakeThemes();
- Task GetThemesRawContent(string url);
}
}
\ No newline at end of file
diff --git a/src/Ombi.Api.Gotify/GotifyApi.cs b/src/Ombi.Api.Gotify/GotifyApi.cs
new file mode 100644
index 000000000..8cd79a689
--- /dev/null
+++ b/src/Ombi.Api.Gotify/GotifyApi.cs
@@ -0,0 +1,36 @@
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace Ombi.Api.Gotify
+{
+ public class GotifyApi : IGotifyApi
+ {
+ public GotifyApi(IApi api)
+ {
+ _api = api;
+ }
+
+ private readonly IApi _api;
+
+ public async Task PushAsync(string baseUrl, string accessToken, string subject, string body, sbyte priority)
+ {
+ var request = new Request("/message", baseUrl, HttpMethod.Post);
+ request.AddQueryString("token", accessToken);
+
+ request.AddHeader("Access-Token", accessToken);
+ request.ApplicationJsonContentType();
+
+
+ var jsonBody = new
+ {
+ message = body,
+ title = subject,
+ priority = priority
+ };
+
+ request.AddJsonBody(jsonBody);
+
+ await _api.Request(request);
+ }
+ }
+}
diff --git a/src/Ombi.Api.Gotify/IGotifyApi.cs b/src/Ombi.Api.Gotify/IGotifyApi.cs
new file mode 100644
index 000000000..e6a6b4060
--- /dev/null
+++ b/src/Ombi.Api.Gotify/IGotifyApi.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace Ombi.Api.Gotify
+{
+ public interface IGotifyApi
+ {
+ Task PushAsync(string endpoint, string accessToken, string subject, string body, sbyte priority);
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj b/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj
new file mode 100644
index 000000000..ce5475fae
--- /dev/null
+++ b/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj
@@ -0,0 +1,15 @@
+
+
+
+ netstandard2.0
+ 3.0.0.0
+ 3.0.0.0
+
+
+
+
+
+
+
+
+
diff --git a/src/Ombi.Api.Lidarr/ILidarrApi.cs b/src/Ombi.Api.Lidarr/ILidarrApi.cs
new file mode 100644
index 000000000..b542ff0a0
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/ILidarrApi.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Ombi.Api.Lidarr.Models;
+
+namespace Ombi.Api.Lidarr
+{
+ public interface ILidarrApi
+ {
+ Task> AlbumLookup(string searchTerm, string apiKey, string baseUrl);
+ Task> ArtistLookup(string searchTerm, string apiKey, string baseUrl);
+ Task> GetProfiles(string apiKey, string baseUrl);
+ Task> GetRootFolders(string apiKey, string baseUrl);
+ Task GetArtist(int artistId, string apiKey, string baseUrl);
+ Task GetArtistByForeignId(string foreignArtistId, string apiKey, string baseUrl);
+ Task GetAlbumsByArtist(string foreignArtistId);
+ Task GetAlbumByForeignId(string foreignArtistId, string apiKey, string baseUrl);
+ Task> GetArtists(string apiKey, string baseUrl);
+ Task> GetAllAlbums(string apiKey, string baseUrl);
+ Task AddArtist(ArtistAdd artist, string apiKey, string baseUrl);
+ Task MontiorAlbum(int albumId, string apiKey, string baseUrl);
+ Task> GetAllAlbumsByArtistId(int artistId, string apiKey, string baseUrl);
+ Task> GetMetadataProfile(string apiKey, string baseUrl);
+ Task Status(string apiKey, string baseUrl);
+ Task AlbumSearch(int[] albumIds, string apiKey, string baseUrl);
+ Task AlbumInformation(string albumId, string apiKey, string baseUrl);
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/LidarrApi.cs b/src/Ombi.Api.Lidarr/LidarrApi.cs
new file mode 100644
index 000000000..dd589c64d
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/LidarrApi.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Ombi.Api.Lidarr.Models;
+
+namespace Ombi.Api.Lidarr
+{
+ public class LidarrApi : ILidarrApi
+ {
+ public LidarrApi(ILogger logger, IApi api)
+ {
+ Api = api;
+ Logger = logger;
+ }
+
+ private IApi Api { get; }
+ private ILogger Logger { get; }
+
+ private const string ApiVersion = "/api/v1";
+
+ public Task> GetProfiles(string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/qualityprofile", baseUrl, HttpMethod.Get);
+
+ AddHeaders(request, apiKey);
+ return Api.Request>(request);
+ }
+
+ public Task> GetRootFolders(string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/rootfolder", baseUrl, HttpMethod.Get);
+
+ AddHeaders(request, apiKey);
+ return Api.Request>(request);
+ }
+
+ public async Task> ArtistLookup(string searchTerm, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/Artist/lookup", baseUrl, HttpMethod.Get);
+ request.AddQueryString("term", searchTerm);
+
+ AddHeaders(request, apiKey);
+ return await Api.Request>(request);
+ }
+
+ public Task> AlbumLookup(string searchTerm, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/Album/lookup", baseUrl, HttpMethod.Get);
+ request.AddQueryString("term", searchTerm);
+
+ AddHeaders(request, apiKey);
+ return Api.Request>(request);
+ }
+
+ public Task GetArtist(int artistId, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/artist/{artistId}", baseUrl, HttpMethod.Get);
+
+ AddHeaders(request, apiKey);
+ return Api.Request(request);
+ }
+
+ public async Task GetArtistByForeignId(string foreignArtistId, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/artist/lookup", baseUrl, HttpMethod.Get);
+
+ request.AddQueryString("term", $"lidarr:{foreignArtistId}");
+ AddHeaders(request, apiKey);
+ return (await Api.Request>(request)).FirstOrDefault();
+ }
+
+ public async Task GetAlbumByForeignId(string foreignArtistId, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/album/lookup", baseUrl, HttpMethod.Get);
+
+ request.AddQueryString("term", $"lidarr:{foreignArtistId}");
+ AddHeaders(request, apiKey);
+ var albums = await Api.Request>(request);
+ return albums.FirstOrDefault();
+ }
+
+ public Task GetAlbumsByArtist(string foreignArtistId)
+ {
+ var request = new Request(string.Empty, $"https://api.lidarr.audio/api/v0.4/artist/{foreignArtistId}",
+ HttpMethod.Get) {IgnoreBaseUrlAppend = true};
+ return Api.Request(request);
+ }
+
+ public Task> GetArtists(string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/artist", baseUrl, HttpMethod.Get);
+
+ AddHeaders(request, apiKey);
+ return Api.Request>(request);
+ }
+
+ public Task> GetAllAlbums(string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
+
+ AddHeaders(request, apiKey);
+ return Api.Request>(request);
+ }
+
+ public async Task AlbumInformation(string albumId, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
+ request.AddQueryString("foreignAlbumId", albumId);
+ AddHeaders(request, apiKey);
+ var albums = await Api.Request>(request);
+ return albums.FirstOrDefault();
+ }
+
+
+ ///
+ /// THIS ONLY SUPPORTS ALBUMS THAT THE ARTIST IS IN LIDARR
+ ///
+ ///
+ ///
+ ///
+ ///
+ public Task> GetTracksForAlbum(int albumId, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
+ request.AddQueryString("albumId", albumId.ToString());
+ AddHeaders(request, apiKey);
+ return Api.Request>(request);
+ }
+
+ public Task AddArtist(ArtistAdd artist, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/artist", baseUrl, HttpMethod.Post);
+ request.AddJsonBody(artist);
+ AddHeaders(request, apiKey);
+ return Api.Request(request);
+ }
+
+ public async Task MontiorAlbum(int albumId, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/album/monitor", baseUrl, HttpMethod.Put);
+ request.AddJsonBody(new
+ {
+ albumIds = new[] { albumId },
+ monitored = true
+ });
+ AddHeaders(request, apiKey);
+ return (await Api.Request>(request)).FirstOrDefault();
+ }
+
+ public Task> GetAllAlbumsByArtistId(int artistId, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
+ request.AddQueryString("artistId", artistId.ToString());
+ AddHeaders(request, apiKey);
+ return Api.Request>(request);
+ }
+
+ public Task> GetMetadataProfile(string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/metadataprofile", baseUrl, HttpMethod.Get);
+ AddHeaders(request, apiKey);
+ return Api.Request>(request);
+ }
+
+ public Task Status(string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/system/status", baseUrl, HttpMethod.Get);
+ AddHeaders(request, apiKey);
+ return Api.Request(request);
+ }
+
+ public Task AlbumSearch(int[] albumIds, string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiVersion}/command/", baseUrl, HttpMethod.Post);
+ request.AddJsonBody(new { name = "AlbumSearch", albumIds });
+ AddHeaders(request, apiKey);
+ return Api.Request(request);
+ }
+
+ private void AddHeaders(Request request, string key)
+ {
+ request.AddHeader("X-Api-Key", key);
+ }
+ }
+}
diff --git a/src/Ombi.Api.Lidarr/Models/AlbumByArtistResponse.cs b/src/Ombi.Api.Lidarr/Models/AlbumByArtistResponse.cs
new file mode 100644
index 000000000..62f19651f
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/AlbumByArtistResponse.cs
@@ -0,0 +1,34 @@
+namespace Ombi.Api.Lidarr.Models
+{
+ public class AlbumByArtistResponse
+ {
+ public Album[] Albums { get; set; }
+ public string ArtistName { get; set; }
+ public string Disambiguation { get; set; }
+ public string Id { get; set; }
+ public Image[] Images { get; set; }
+ public Link[] Links { get; set; }
+ public string Overview { get; set; }
+ public Rating Rating { get; set; }
+ public string SortName { get; set; }
+ public string Status { get; set; }
+ public string Type { get; set; }
+ }
+
+ public class Rating
+ {
+ public int Count { get; set; }
+ public decimal Value { get; set; }
+ }
+
+ public class Album
+ {
+ public string Disambiguation { get; set; }
+ public string Id { get; set; }
+ public string ReleaseDate { get; set; }
+ public string[] ReleaseStatuses { get; set; }
+ public string[] SecondaryTypes { get; set; }
+ public string Title { get; set; }
+ public string Type { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/AlbumByForeignId.cs b/src/Ombi.Api.Lidarr/Models/AlbumByForeignId.cs
new file mode 100644
index 000000000..27a479d2f
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/AlbumByForeignId.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Net.Mime;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class AlbumByForeignId
+ {
+ public string title { get; set; }
+ public string disambiguation { get; set; }
+ public string overview { get; set; }
+ public int artistId { get; set; }
+ public string foreignAlbumId { get; set; }
+ public bool monitored { get; set; }
+ public bool anyReleaseOk { get; set; }
+ public int profileId { get; set; }
+ public int duration { get; set; }
+ public string albumType { get; set; }
+ public object[] secondaryTypes { get; set; }
+ public int mediumCount { get; set; }
+ public Ratings ratings { get; set; }
+ public DateTime releaseDate { get; set; }
+ public Release[] releases { get; set; }
+ public object[] genres { get; set; }
+ public Medium[] media { get; set; }
+ public Artist artist { get; set; }
+ public Image[] images { get; set; }
+ public Link[] links { get; set; }
+ public Statistics statistics { get; set; }
+ public int id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/AlbumLookup.cs b/src/Ombi.Api.Lidarr/Models/AlbumLookup.cs
new file mode 100644
index 000000000..1e909cf4c
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/AlbumLookup.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class AlbumLookup
+ {
+ public string title { get; set; }
+ public string status { get; set; }
+ public string artistType { get; set; }
+ public string disambiguation { get; set; }
+ public List links { get; set; }
+ public int artistId { get; set; }
+ public string foreignAlbumId { get; set; }
+ public bool monitored { get; set; }
+ public int profileId { get; set; }
+ public int duration { get; set; }
+ public string albumType { get; set; }
+ public string[] secondaryTypes { get; set; }
+ public int mediumCount { get; set; }
+ public Ratings ratings { get; set; }
+ public DateTime releaseDate { get; set; }
+ //public object[] releases { get; set; }
+ public object[] genres { get; set; }
+ //public object[] media { get; set; }
+ public Artist artist { get; set; }
+ public Image[] images { get; set; }
+ public string remoteCover { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/AlbumResponse.cs b/src/Ombi.Api.Lidarr/Models/AlbumResponse.cs
new file mode 100644
index 000000000..f9d35c43b
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/AlbumResponse.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class AlbumResponse
+ {
+ public string title { get; set; }
+ public string disambiguation { get; set; }
+ public int artistId { get; set; }
+ public string foreignAlbumId { get; set; }
+ public bool monitored { get; set; }
+ public int profileId { get; set; }
+ public int duration { get; set; }
+ public string albumType { get; set; }
+ public object[] secondaryTypes { get; set; }
+ public int mediumCount { get; set; }
+ public Ratings ratings { get; set; }
+ public DateTime releaseDate { get; set; }
+ public Currentrelease currentRelease { get; set; }
+ public Release[] releases { get; set; }
+ public object[] genres { get; set; }
+ public Medium[] media { get; set; }
+ public Image[] images { get; set; }
+ public Statistics statistics { get; set; }
+ public int id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/Artist.cs b/src/Ombi.Api.Lidarr/Models/Artist.cs
new file mode 100644
index 000000000..bc6afc20e
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/Artist.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class Artist
+ {
+ public string status { get; set; }
+ public bool ended { get; set; }
+ public string artistName { get; set; }
+ public string foreignArtistId { get; set; }
+ public int tadbId { get; set; }
+ public int discogsId { get; set; }
+ public object[] links { get; set; }
+ public object[] images { get; set; }
+ public int qualityProfileId { get; set; }
+ public int languageProfileId { get; set; }
+ public int metadataProfileId { get; set; }
+ public bool albumFolder { get; set; }
+ public bool monitored { get; set; }
+ public object[] genres { get; set; }
+ public object[] tags { get; set; }
+ public DateTime added { get; set; }
+ public Statistics statistics { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/ArtistAdd.cs b/src/Ombi.Api.Lidarr/Models/ArtistAdd.cs
new file mode 100644
index 000000000..e292e8905
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/ArtistAdd.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Net.Mime;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class ArtistAdd
+ {
+ public string status { get; set; }
+ public bool ended { get; set; }
+ public string artistName { get; set; }
+ public string foreignArtistId { get; set; }
+ public int tadbId { get; set; }
+ public int discogsId { get; set; }
+ public string overview { get; set; }
+ public string disambiguation { get; set; }
+ public Link[] links { get; set; }
+ public Image[] images { get; set; }
+ public string remotePoster { get; set; }
+ public int qualityProfileId { get; set; }
+ public int metadataProfileId { get; set; }
+ public bool albumFolder { get; set; }
+ public bool monitored { get; set; }
+ public string cleanName { get; set; }
+ public string sortName { get; set; }
+ public object[] tags { get; set; }
+ public DateTime added { get; set; }
+ public Ratings ratings { get; set; }
+ public Statistics statistics { get; set; }
+ public Addoptions addOptions { get; set; }
+ public string rootFolderPath { get; set; }
+ }
+
+ public class Addoptions
+ {
+ ///
+ /// Future = 1
+ /// Missing = 2
+ /// Existing = 3
+ /// First = 5
+ /// Latest = 4
+ /// None = 6
+ ///
+ public int selectedOption { get; set; }
+ public bool monitored { get; set; }
+ public bool searchForMissingAlbums { get; set; }
+ public string[] AlbumsToMonitor { get; set; } // Uses the MusicBrainzAlbumId!
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/ArtistLookup.cs b/src/Ombi.Api.Lidarr/Models/ArtistLookup.cs
new file mode 100644
index 000000000..aa454c0a0
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/ArtistLookup.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Net.Mime;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class ArtistLookup
+ {
+ public string status { get; set; }
+ public bool ended { get; set; }
+ public string artistName { get; set; }
+ public string foreignArtistId { get; set; }
+ public int tadbId { get; set; }
+ public int discogsId { get; set; }
+ public string overview { get; set; }
+ public string artistType { get; set; }
+ public string disambiguation { get; set; }
+ public Link[] links { get; set; }
+ public Image[] images { get; set; }
+ public string remotePoster { get; set; }
+ public int qualityProfileId { get; set; }
+ public int languageProfileId { get; set; }
+ public int metadataProfileId { get; set; }
+ public bool albumFolder { get; set; }
+ public bool monitored { get; set; }
+ public string cleanName { get; set; }
+ public string sortName { get; set; }
+ public object[] tags { get; set; }
+ public DateTime added { get; set; }
+ public Ratings ratings { get; set; }
+ public Statistics statistics { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/ArtistResult.cs b/src/Ombi.Api.Lidarr/Models/ArtistResult.cs
new file mode 100644
index 000000000..32b3aaab5
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/ArtistResult.cs
@@ -0,0 +1,93 @@
+using System;
+
+namespace Ombi.Api.Lidarr.Models
+{
+
+ public class ArtistResult
+ {
+ public string status { get; set; }
+ public bool ended { get; set; }
+ public DateTime lastInfoSync { get; set; }
+ public string artistName { get; set; }
+ public string foreignArtistId { get; set; }
+ public int tadbId { get; set; }
+ public int discogsId { get; set; }
+ public string overview { get; set; }
+ public string artistType { get; set; }
+ public string disambiguation { get; set; }
+ public Link[] links { get; set; }
+ public Nextalbum nextAlbum { get; set; }
+ public Image[] images { get; set; }
+ public string path { get; set; }
+ public int qualityProfileId { get; set; }
+ public int languageProfileId { get; set; }
+ public int metadataProfileId { get; set; }
+ public bool albumFolder { get; set; }
+ public bool monitored { get; set; }
+ public object[] genres { get; set; }
+ public string cleanName { get; set; }
+ public string sortName { get; set; }
+ public object[] tags { get; set; }
+ public DateTime added { get; set; }
+ public Ratings ratings { get; set; }
+ public Statistics statistics { get; set; }
+ public int id { get; set; }
+ }
+
+ public class Nextalbum
+ {
+ public string foreignAlbumId { get; set; }
+ public int artistId { get; set; }
+ public string title { get; set; }
+ public string disambiguation { get; set; }
+ public string cleanTitle { get; set; }
+ public DateTime releaseDate { get; set; }
+ public int profileId { get; set; }
+ public int duration { get; set; }
+ public bool monitored { get; set; }
+ public object[] images { get; set; }
+ public object[] genres { get; set; }
+ public Medium[] media { get; set; }
+ public DateTime lastInfoSync { get; set; }
+ public DateTime added { get; set; }
+ public string albumType { get; set; }
+ public object[] secondaryTypes { get; set; }
+ public Ratings ratings { get; set; }
+ public Release[] releases { get; set; }
+ public Currentrelease currentRelease { get; set; }
+ public int id { get; set; }
+ }
+
+ public class Currentrelease
+ {
+ public string id { get; set; }
+ public string title { get; set; }
+ public DateTime releaseDate { get; set; }
+ public int trackCount { get; set; }
+ public int mediaCount { get; set; }
+ public string disambiguation { get; set; }
+ public string[] country { get; set; }
+ public string format { get; set; }
+ public string[] label { get; set; }
+ }
+
+ public class Medium
+ {
+ public int number { get; set; }
+ public string name { get; set; }
+ public string format { get; set; }
+ }
+
+ public class Release
+ {
+ public string id { get; set; }
+ public string title { get; set; }
+ public DateTime releaseDate { get; set; }
+ public int trackCount { get; set; }
+ public int mediaCount { get; set; }
+ public string disambiguation { get; set; }
+ public string[] country { get; set; }
+ public string format { get; set; }
+ public string[] label { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/CommandResult.cs b/src/Ombi.Api.Lidarr/Models/CommandResult.cs
new file mode 100644
index 000000000..5271de91f
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/CommandResult.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Ombi.Api.Lidarr.Models
+{
+
+ public class CommandResult
+ {
+ public string name { get; set; }
+ public DateTime queued { get; set; }
+ public DateTime stateChangeTime { get; set; }
+ public bool sendUpdatesToClient { get; set; }
+ public string status { get; set; }
+ public int id { get; set; }
+ }
+}
diff --git a/src/Ombi.Api.Lidarr/Models/Image.cs b/src/Ombi.Api.Lidarr/Models/Image.cs
new file mode 100644
index 000000000..172a13fe9
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/Image.cs
@@ -0,0 +1,8 @@
+namespace Ombi.Api.Lidarr.Models
+{
+ public class Image
+ {
+ public string coverType { get; set; }
+ public string url { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/LidarrLinks.cs b/src/Ombi.Api.Lidarr/Models/LidarrLinks.cs
new file mode 100644
index 000000000..e8bdb8975
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/LidarrLinks.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class LidarrLinks
+ {
+ public string url { get; set; }
+ public string name { get; set; }
+ }
+}
diff --git a/src/Ombi.Api.Lidarr/Models/LidarrProfile.cs b/src/Ombi.Api.Lidarr/Models/LidarrProfile.cs
new file mode 100644
index 000000000..19ebda5a6
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/LidarrProfile.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class Quality
+ {
+ public int id { get; set; }
+ public string name { get; set; }
+ }
+
+ public class Item
+ {
+ public Quality quality { get; set; }
+ public bool allowed { get; set; }
+ }
+
+ public class LidarrProfile
+{
+ public string name { get; set; }
+ public List- items { get; set; }
+ public int id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/LidarrRatings.cs b/src/Ombi.Api.Lidarr/Models/LidarrRatings.cs
new file mode 100644
index 000000000..7728d58bf
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/LidarrRatings.cs
@@ -0,0 +1,8 @@
+namespace Ombi.Api.Lidarr.Models
+{
+ public class LidarrRatings
+ {
+ public int votes { get; set; }
+ public decimal value { get; set; }
+ }
+}
diff --git a/src/Ombi.Api.Lidarr/Models/LidarrRootFolder.cs b/src/Ombi.Api.Lidarr/Models/LidarrRootFolder.cs
new file mode 100644
index 000000000..a3a252f04
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/LidarrRootFolder.cs
@@ -0,0 +1,11 @@
+namespace Ombi.Api.Lidarr.Models
+{
+ public class LidarrRootFolder
+ {
+ public string path { get; set; }
+ public long freeSpace { get; set; }
+ public object[] unmappedFolders { get; set; }
+ public int id { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/LidarrStatus.cs b/src/Ombi.Api.Lidarr/Models/LidarrStatus.cs
new file mode 100644
index 000000000..27f6c1820
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/LidarrStatus.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class LidarrStatus
+ {
+ public string version { get; set; }
+ public DateTime buildTime { get; set; }
+ public bool isDebug { get; set; }
+ public bool isProduction { get; set; }
+ public bool isAdmin { get; set; }
+ public bool isUserInteractive { get; set; }
+ public string startupPath { get; set; }
+ public string appData { get; set; }
+ public string osName { get; set; }
+ public string osVersion { get; set; }
+ public bool isMonoRuntime { get; set; }
+ public bool isMono { get; set; }
+ public bool isLinux { get; set; }
+ public bool isOsx { get; set; }
+ public bool isWindows { get; set; }
+ public string mode { get; set; }
+ public string branch { get; set; }
+ public string authentication { get; set; }
+ public string sqliteVersion { get; set; }
+ public int migrationVersion { get; set; }
+ public string urlBase { get; set; }
+ public string runtimeVersion { get; set; }
+ public string runtimeName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/LidarrTrack.cs b/src/Ombi.Api.Lidarr/Models/LidarrTrack.cs
new file mode 100644
index 000000000..367e8cc7c
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/LidarrTrack.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Ombi.Api.Lidarr.Models
+{
+ public class LidarrTrack
+ {
+ public int artistId { get; set; }
+ public int trackFileId { get; set; }
+ public int albumId { get; set; }
+ public bool _explicit { get; set; }
+ public int absoluteTrackNumber { get; set; }
+ public string trackNumber { get; set; }
+ public string title { get; set; }
+ public int duration { get; set; }
+ public int mediumNumber { get; set; }
+ public bool hasFile { get; set; }
+ public bool monitored { get; set; }
+ public int id { get; set; }
+ }
+}
diff --git a/src/Ombi.Api.Lidarr/Models/Link.cs b/src/Ombi.Api.Lidarr/Models/Link.cs
new file mode 100644
index 000000000..492ac0426
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/Link.cs
@@ -0,0 +1,8 @@
+namespace Ombi.Api.Lidarr.Models
+{
+ public class Link
+ {
+ public string url { get; set; }
+ public string name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/MetadataProfile.cs b/src/Ombi.Api.Lidarr/Models/MetadataProfile.cs
new file mode 100644
index 000000000..bda3333f1
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/MetadataProfile.cs
@@ -0,0 +1,8 @@
+namespace Ombi.Api.Lidarr.Models
+{
+ public class MetadataProfile
+ {
+ public string name { get; set; }
+ public int id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/Ratings.cs b/src/Ombi.Api.Lidarr/Models/Ratings.cs
new file mode 100644
index 000000000..f2aac4203
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/Ratings.cs
@@ -0,0 +1,8 @@
+namespace Ombi.Api.Lidarr.Models
+{
+ public class Ratings
+ {
+ public int votes { get; set; }
+ public decimal value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Models/Statistics.cs b/src/Ombi.Api.Lidarr/Models/Statistics.cs
new file mode 100644
index 000000000..77c6b5217
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Models/Statistics.cs
@@ -0,0 +1,12 @@
+namespace Ombi.Api.Lidarr.Models
+{
+ public class Statistics
+ {
+ public int albumCount { get; set; }
+ public int trackFileCount { get; set; }
+ public int trackCount { get; set; }
+ public int totalTrackCount { get; set; }
+ public long sizeOnDisk { get; set; }
+ public decimal percentOfEpisodes { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Lidarr/Ombi.Api.Lidarr.csproj b/src/Ombi.Api.Lidarr/Ombi.Api.Lidarr.csproj
new file mode 100644
index 000000000..a3651df3c
--- /dev/null
+++ b/src/Ombi.Api.Lidarr/Ombi.Api.Lidarr.csproj
@@ -0,0 +1,11 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
diff --git a/src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj b/src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj
index 83318be7b..98292f463 100644
--- a/src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj
+++ b/src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Ombi.Api.Notifications/IOneSignalApi.cs b/src/Ombi.Api.Notifications/IOneSignalApi.cs
index 2e3ef106e..6de64d11e 100644
--- a/src/Ombi.Api.Notifications/IOneSignalApi.cs
+++ b/src/Ombi.Api.Notifications/IOneSignalApi.cs
@@ -6,6 +6,6 @@ namespace Ombi.Api.Notifications
{
public interface IOneSignalApi
{
- Task PushNotification(List playerIds, string message);
+ Task PushNotification(List playerIds, string message, bool isAdminNotification, int requestId, int requestType);
}
}
\ No newline at end of file
diff --git a/src/Ombi.Api.Notifications/Models/OneSignalNotificationBody.cs b/src/Ombi.Api.Notifications/Models/OneSignalNotificationBody.cs
index 6c024fa67..e65222bd5 100644
--- a/src/Ombi.Api.Notifications/Models/OneSignalNotificationBody.cs
+++ b/src/Ombi.Api.Notifications/Models/OneSignalNotificationBody.cs
@@ -4,18 +4,22 @@
{
public string app_id { get; set; }
public string[] include_player_ids { get; set; }
- public Data data { get; set; }
+ public object data { get; set; }
+ public Button[] buttons { get; set; }
public Contents contents { get; set; }
}
- public class Data
- {
- public string foo { get; set; }
- }
public class Contents
{
public string en { get; set; }
}
+ public class Button
+ {
+ public string id { get; set; }
+ public string text { get; set; }
+ //public string icon { get; set; }
+ }
+
}
\ No newline at end of file
diff --git a/src/Ombi.Api.Notifications/Ombi.Api.Notifications.csproj b/src/Ombi.Api.Notifications/Ombi.Api.Notifications.csproj
index a3651df3c..7b890e2dd 100644
--- a/src/Ombi.Api.Notifications/Ombi.Api.Notifications.csproj
+++ b/src/Ombi.Api.Notifications/Ombi.Api.Notifications.csproj
@@ -4,6 +4,10 @@
netstandard2.0
+
+
+
+
diff --git a/src/Ombi.Api.Notifications/OneSignalApi.cs b/src/Ombi.Api.Notifications/OneSignalApi.cs
index d4760bb09..ee5c7e44a 100644
--- a/src/Ombi.Api.Notifications/OneSignalApi.cs
+++ b/src/Ombi.Api.Notifications/OneSignalApi.cs
@@ -20,13 +20,13 @@ namespace Ombi.Api.Notifications
private readonly IApplicationConfigRepository _appConfig;
private const string ApiUrl = "https://onesignal.com/api/v1/notifications";
- public async Task PushNotification(List playerIds, string message)
+ public async Task PushNotification(List playerIds, string message, bool isAdminNotification, int requestId, int requestType)
{
if (!playerIds.Any())
{
return null;
}
- var id = await _appConfig.Get(ConfigurationTypes.Notification);
+ var id = await _appConfig.GetAsync(ConfigurationTypes.Notification);
var request = new Request(string.Empty, ApiUrl, HttpMethod.Post);
var body = new OneSignalNotificationBody
@@ -39,6 +39,17 @@ namespace Ombi.Api.Notifications
include_player_ids = playerIds.ToArray()
};
+ if (isAdminNotification)
+ {
+ // Add the action buttons
+ body.data = new { requestid = requestId, requestType = requestType};
+ body.buttons = new[]
+ {
+ new Button {id = "approve", text = "Approve Request"},
+ new Button {id = "deny", text = "Deny Request"},
+ };
+ }
+
request.AddJsonBody(body);
var result = await _api.Request(request);
diff --git a/src/Ombi.Api.Plex/IPlexApi.cs b/src/Ombi.Api.Plex/IPlexApi.cs
index 2dd1a638f..c79ec50c9 100644
--- a/src/Ombi.Api.Plex/IPlexApi.cs
+++ b/src/Ombi.Api.Plex/IPlexApi.cs
@@ -11,6 +11,7 @@ namespace Ombi.Api.Plex
public interface IPlexApi
{
Task GetStatus(string authToken, string uri);
+ Task GetLibrariesForMachineId(string authToken, string machineId);
Task SignIn(UserRequest user);
Task GetServer(string authToken);
Task GetLibrarySections(string authToken, string plexFullHost);
@@ -23,6 +24,7 @@ namespace Ombi.Api.Plex
Task GetAccount(string authToken);
Task GetRecentlyAdded(string authToken, string uri, string sectionId);
Task GetPin(int pinId);
- Task GetOAuthUrl(int pinId, string code, string applicationUrl, bool wizard);
+ Task GetOAuthUrl(string code, string applicationUrl);
+ Task AddUser(string emailAddress, string serverId, string authToken, int[] libs);
}
}
\ No newline at end of file
diff --git a/src/Ombi.Api.Plex/Models/PlexAdd.cs b/src/Ombi.Api.Plex/Models/PlexAdd.cs
new file mode 100644
index 000000000..fb0a550d0
--- /dev/null
+++ b/src/Ombi.Api.Plex/Models/PlexAdd.cs
@@ -0,0 +1,84 @@
+using System.Collections.Generic;
+using System.Xml.Serialization;
+
+namespace Ombi.Api.Plex.Models
+{
+ [XmlRoot(ElementName = "Section")]
+ public class Section
+ {
+ [XmlAttribute(AttributeName = "id")]
+ public string Id { get; set; }
+ [XmlAttribute(AttributeName = "key")]
+ public string Key { get; set; }
+ [XmlAttribute(AttributeName = "title")]
+ public string Title { get; set; }
+ [XmlAttribute(AttributeName = "type")]
+ public string Type { get; set; }
+ [XmlAttribute(AttributeName = "shared")]
+ public string Shared { get; set; }
+ }
+
+ [XmlRoot(ElementName = "SharedServer")]
+ public class SharedServer
+ {
+ [XmlElement(ElementName = "Section")]
+ public List Section { get; set; }
+ [XmlAttribute(AttributeName = "id")]
+ public string Id { get; set; }
+ [XmlAttribute(AttributeName = "username")]
+ public string Username { get; set; }
+ [XmlAttribute(AttributeName = "email")]
+ public string Email { get; set; }
+ [XmlAttribute(AttributeName = "userID")]
+ public string UserID { get; set; }
+ [XmlAttribute(AttributeName = "accessToken")]
+ public string AccessToken { get; set; }
+ [XmlAttribute(AttributeName = "name")]
+ public string Name { get; set; }
+ [XmlAttribute(AttributeName = "acceptedAt")]
+ public string AcceptedAt { get; set; }
+ [XmlAttribute(AttributeName = "invitedAt")]
+ public string InvitedAt { get; set; }
+ [XmlAttribute(AttributeName = "allowSync")]
+ public string AllowSync { get; set; }
+ [XmlAttribute(AttributeName = "allowCameraUpload")]
+ public string AllowCameraUpload { get; set; }
+ [XmlAttribute(AttributeName = "allowChannels")]
+ public string AllowChannels { get; set; }
+ [XmlAttribute(AttributeName = "allowTuners")]
+ public string AllowTuners { get; set; }
+ [XmlAttribute(AttributeName = "owned")]
+ public string Owned { get; set; }
+ }
+
+ [XmlRoot(ElementName = "MediaContainer")]
+ public class PlexAdd
+ {
+ [XmlElement(ElementName = "SharedServer")]
+ public SharedServer SharedServer { get; set; }
+ [XmlAttribute(AttributeName = "friendlyName")]
+ public string FriendlyName { get; set; }
+ [XmlAttribute(AttributeName = "identifier")]
+ public string Identifier { get; set; }
+ [XmlAttribute(AttributeName = "machineIdentifier")]
+ public string MachineIdentifier { get; set; }
+ [XmlAttribute(AttributeName = "size")]
+ public string Size { get; set; }
+ }
+
+ [XmlRoot(ElementName = "Response")]
+ public class AddUserError
+ {
+ [XmlAttribute(AttributeName = "code")]
+ public string Code { get; set; }
+ [XmlAttribute(AttributeName = "status")]
+ public string Status { get; set; }
+ }
+
+ public class PlexAddWrapper
+ {
+ public PlexAdd Add { get; set; }
+ public AddUserError Error { get; set; }
+ public bool HasError => Error != null;
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Plex/Models/PlexLibrariesForMachineId.cs b/src/Ombi.Api.Plex/Models/PlexLibrariesForMachineId.cs
new file mode 100644
index 000000000..17ac59b81
--- /dev/null
+++ b/src/Ombi.Api.Plex/Models/PlexLibrariesForMachineId.cs
@@ -0,0 +1,66 @@
+namespace Ombi.Api.Plex.Models
+{
+
+ using System;
+ using System.Xml.Serialization;
+ using System.Collections.Generic;
+
+ [XmlRoot(ElementName = "Section")]
+ public class SectionLite
+ {
+ [XmlAttribute(AttributeName = "id")]
+ public string Id { get; set; }
+ [XmlAttribute(AttributeName = "key")]
+ public string Key { get; set; }
+ [XmlAttribute(AttributeName = "type")]
+ public string Type { get; set; }
+ [XmlAttribute(AttributeName = "title")]
+ public string Title { get; set; }
+ }
+
+ [XmlRoot(ElementName = "Server")]
+ public class ServerLib
+ {
+ [XmlElement(ElementName = "Section")]
+ public List Section { get; set; }
+ [XmlAttribute(AttributeName = "name")]
+ public string Name { get; set; }
+ [XmlAttribute(AttributeName = "address")]
+ public string Address { get; set; }
+ [XmlAttribute(AttributeName = "port")]
+ public string Port { get; set; }
+ [XmlAttribute(AttributeName = "version")]
+ public string Version { get; set; }
+ [XmlAttribute(AttributeName = "scheme")]
+ public string Scheme { get; set; }
+ [XmlAttribute(AttributeName = "host")]
+ public string Host { get; set; }
+ [XmlAttribute(AttributeName = "localAddresses")]
+ public string LocalAddresses { get; set; }
+ [XmlAttribute(AttributeName = "machineIdentifier")]
+ public string MachineIdentifier { get; set; }
+ [XmlAttribute(AttributeName = "createdAt")]
+ public string CreatedAt { get; set; }
+ [XmlAttribute(AttributeName = "updatedAt")]
+ public string UpdatedAt { get; set; }
+ [XmlAttribute(AttributeName = "owned")]
+ public string Owned { get; set; }
+ [XmlAttribute(AttributeName = "synced")]
+ public string Synced { get; set; }
+ }
+
+ [XmlRoot(ElementName = "MediaContainer")]
+ public class PlexLibrariesForMachineId
+ {
+ [XmlElement(ElementName = "Server")]
+ public ServerLib Server { get; set; }
+ [XmlAttribute(AttributeName = "friendlyName")]
+ public string FriendlyName { get; set; }
+ [XmlAttribute(AttributeName = "identifier")]
+ public string Identifier { get; set; }
+ [XmlAttribute(AttributeName = "machineIdentifier")]
+ public string MachineIdentifier { get; set; }
+ [XmlAttribute(AttributeName = "size")]
+ public string Size { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Plex/PlexApi.cs b/src/Ombi.Api.Plex/PlexApi.cs
index 4276f6203..eaafcd75f 100644
--- a/src/Ombi.Api.Plex/PlexApi.cs
+++ b/src/Ombi.Api.Plex/PlexApi.cs
@@ -41,7 +41,18 @@ namespace Ombi.Api.Plex
}
else
{
- _app = settings.ApplicationName;
+ // Check for non-ascii characters (New .Net Core HTTPLib does not allow this)
+ var chars = settings.ApplicationName.ToCharArray();
+ var hasNonAscii = false;
+ foreach (var c in chars)
+ {
+ if (c > 128)
+ {
+ hasNonAscii = true;
+ }
+ }
+
+ _app = hasNonAscii ? "Ombi" : settings.ApplicationName;
}
return _app;
@@ -116,6 +127,13 @@ namespace Ombi.Api.Plex
return await Api.Request(request);
}
+ public async Task GetLibrariesForMachineId(string authToken, string machineId)
+ {
+ var request = new Request("", $"https://plex.tv/api/servers/{machineId}", HttpMethod.Get, ContentType.Xml);
+ await AddHeaders(request, authToken);
+ return await Api.Request(request);
+ }
+
///
// 192.168.1.69:32400/library/metadata/3662/allLeaves
// The metadata ratingkey should be in the Cache
@@ -199,22 +217,17 @@ namespace Ombi.Api.Plex
return await Api.Request(request);
}
- public async Task GetOAuthUrl(int pinId, string code, string applicationUrl, bool wizard)
+ public async Task GetOAuthUrl(string code, string applicationUrl)
{
var request = new Request("auth#", "https://app.plex.tv", HttpMethod.Get);
await AddHeaders(request);
- var forwardUrl = wizard
- ? new Request($"Wizard/OAuth/{pinId}", applicationUrl, HttpMethod.Get)
- : new Request($"Login/OAuth/{pinId}", applicationUrl, HttpMethod.Get);
-
- request.AddQueryString("forwardUrl", forwardUrl.FullUri.ToString());
- request.AddQueryString("pinID", pinId.ToString());
+
request.AddQueryString("code", code);
request.AddQueryString("context[device][product]", ApplicationName);
request.AddQueryString("context[device][environment]", "bundled");
request.AddQueryString("context[device][layout]", "desktop");
request.AddQueryString("context[device][platform]", "Web");
- request.AddQueryString("context[device][device]", "Ombi (Web)");
+ request.AddQueryString("context[device][device]", "Ombi");
var s = await GetSettings();
await CheckInstallId(s);
@@ -232,6 +245,34 @@ namespace Ombi.Api.Plex
return request.FullUri;
}
+ public async Task AddUser(string emailAddress, string serverId, string authToken, int[] libs)
+ {
+ var request = new Request(string.Empty, $"https://plex.tv/api/servers/{serverId}/shared_servers", HttpMethod.Post, ContentType.Xml);
+ await AddHeaders(request, authToken);
+ request.AddJsonBody(new
+ {
+ server_id = serverId,
+ shared_server = new
+ {
+ library_section_ids = libs.Length > 0 ? libs : new int[]{},
+ invited_email = emailAddress
+ },
+ sharing_settings = new { }
+ });
+ var result = await Api.RequestContent(request);
+ try
+ {
+ var add = Api.DeserializeXml(result);
+ return new PlexAddWrapper{Add = add};
+ }
+ catch (InvalidOperationException)
+ {
+ var error = Api.DeserializeXml(result);
+ return new PlexAddWrapper{Error = error};
+ }
+ }
+
+
///
/// Adds the required headers and also the authorization header
///
@@ -254,7 +295,7 @@ namespace Ombi.Api.Plex
request.AddHeader("X-Plex-Client-Identifier", s.InstallId.ToString("N"));
request.AddHeader("X-Plex-Product", ApplicationName);
request.AddHeader("X-Plex-Version", "3");
- request.AddHeader("X-Plex-Device", "Ombi (Web)");
+ request.AddHeader("X-Plex-Device", "Ombi");
request.AddHeader("X-Plex-Platform", "Web");
request.AddContentHeader("Content-Type", request.ContentType == ContentType.Json ? "application/json" : "application/xml");
request.AddHeader("Accept", "application/json");
diff --git a/src/Ombi.Api.Pushover/IPushoverApi.cs b/src/Ombi.Api.Pushover/IPushoverApi.cs
index 42e8e9060..554a15b60 100644
--- a/src/Ombi.Api.Pushover/IPushoverApi.cs
+++ b/src/Ombi.Api.Pushover/IPushoverApi.cs
@@ -5,6 +5,6 @@ namespace Ombi.Api.Pushover
{
public interface IPushoverApi
{
- Task PushAsync(string accessToken, string message, string userToken);
+ Task PushAsync(string accessToken, string message, string userToken, sbyte priority, string sound);
}
}
\ No newline at end of file
diff --git a/src/Ombi.Api.Pushover/PushoverApi.cs b/src/Ombi.Api.Pushover/PushoverApi.cs
index fd6ca23ea..41df0f647 100644
--- a/src/Ombi.Api.Pushover/PushoverApi.cs
+++ b/src/Ombi.Api.Pushover/PushoverApi.cs
@@ -2,6 +2,7 @@
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
+using System.Web;
using Ombi.Api.Pushover.Models;
namespace Ombi.Api.Pushover
@@ -16,13 +17,9 @@ namespace Ombi.Api.Pushover
private readonly IApi _api;
private const string PushoverEndpoint = "https://api.pushover.net/1";
- public async Task PushAsync(string accessToken, string message, string userToken)
+ public async Task PushAsync(string accessToken, string message, string userToken, sbyte priority, string sound)
{
- if (message.Contains("'"))
- {
- message = message.Replace("'", "'");
- }
- var request = new Request($"messages.json?token={accessToken}&user={userToken}&message={WebUtility.HtmlEncode(message)}", PushoverEndpoint, HttpMethod.Post);
+ var request = new Request($"messages.json?token={accessToken}&user={userToken}&priority={priority}&sound={sound}&message={WebUtility.UrlEncode(message)}", PushoverEndpoint, HttpMethod.Post);
var result = await _api.Request(request);
return result;
diff --git a/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj b/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj
index 0c615f301..9f25a7946 100644
--- a/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj
+++ b/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Ombi.Api.Radarr/RadarrApi.cs b/src/Ombi.Api.Radarr/RadarrApi.cs
index 1f897b60b..fd4deb140 100644
--- a/src/Ombi.Api.Radarr/RadarrApi.cs
+++ b/src/Ombi.Api.Radarr/RadarrApi.cs
@@ -79,7 +79,7 @@ namespace Ombi.Api.Radarr
tmdbId = tmdbId,
qualityProfileId = qualityId,
rootFolderPath = rootPath,
- titleSlug = title,
+ titleSlug = title + year,
monitored = true,
year = year,
minimumAvailability = minimumAvailability
diff --git a/src/Ombi.Api.Service/Ombi.Api.Service.csproj b/src/Ombi.Api.Service/Ombi.Api.Service.csproj
index 8cbddd874..bd53c9808 100644
--- a/src/Ombi.Api.Service/Ombi.Api.Service.csproj
+++ b/src/Ombi.Api.Service/Ombi.Api.Service.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Ombi.Api.Sonarr/ISonarrV3Api.cs b/src/Ombi.Api.Sonarr/ISonarrV3Api.cs
new file mode 100644
index 000000000..1d3ea3468
--- /dev/null
+++ b/src/Ombi.Api.Sonarr/ISonarrV3Api.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Ombi.Api.Sonarr.Models;
+using System.Net.Http;
+using Ombi.Api.Sonarr.Models.V3;
+
+namespace Ombi.Api.Sonarr
+{
+ public interface ISonarrV3Api : ISonarrApi
+ {
+ Task> LanguageProfiles(string apiKey, string baseUrl);
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Sonarr/Models/Episode.cs b/src/Ombi.Api.Sonarr/Models/Episode.cs
index c17f5486c..b01e6fd8c 100644
--- a/src/Ombi.Api.Sonarr/Models/Episode.cs
+++ b/src/Ombi.Api.Sonarr/Models/Episode.cs
@@ -6,6 +6,30 @@ namespace Ombi.Api.Sonarr.Models
{
public class Episode
{
+ public Episode()
+ {
+
+ }
+
+ public Episode(Episode ep)
+ {
+ seriesId = ep.seriesId;
+ episodeFileId = ep.episodeFileId;
+ seasonNumber = ep.seasonNumber;
+ episodeNumber = ep.episodeNumber;
+ title = ep.title;
+ airDate = ep.airDate;
+ airDateUtc = ep.airDateUtc;
+ overview = ep.overview;
+ hasFile = ep.hasFile;
+ monitored = ep.monitored;
+ unverifiedSceneNumbering = ep.unverifiedSceneNumbering;
+ id = ep.id;
+ absoluteEpisodeNumber = ep.absoluteEpisodeNumber;
+ sceneAbsoluteEpisodeNumber = ep.sceneAbsoluteEpisodeNumber;
+ sceneEpisodeNumber = ep.sceneEpisodeNumber;
+ sceneSeasonNumber = ep.sceneSeasonNumber;
+ }
public int seriesId { get; set; }
public int episodeFileId { get; set; }
public int seasonNumber { get; set; }
@@ -27,6 +51,24 @@ namespace Ombi.Api.Sonarr.Models
public class Episodefile
{
+ public Episodefile()
+ {
+
+ }
+
+ public Episodefile(Episodefile e)
+ {
+ seriesId = e.seriesId;
+ seasonNumber = e.seasonNumber;
+ relativePath = e.relativePath;
+ path = e.path;
+ size = e.size;
+ dateAdded = e.dateAdded;
+ sceneName = e.sceneName;
+ quality = new EpisodeQuality(e.quality);
+ qualityCutoffNotMet = e.qualityCutoffNotMet;
+ id = e.id;
+ }
public int seriesId { get; set; }
public int seasonNumber { get; set; }
public string relativePath { get; set; }
@@ -41,12 +83,32 @@ namespace Ombi.Api.Sonarr.Models
public class EpisodeQuality
{
+ public EpisodeQuality()
+ {
+
+ }
+
+ public EpisodeQuality(EpisodeQuality e)
+ {
+ quality = new Quality(e.quality);
+ revision = new Revision(e.revision);
+ }
public Quality quality { get; set; }
public Revision revision { get; set; }
}
public class Revision
{
+ public Revision()
+ {
+
+ }
+
+ public Revision(Revision r)
+ {
+ version = r.version;
+ real = r.real;
+ }
public int version { get; set; }
public int real { get; set; }
}
diff --git a/src/Ombi.Api.Sonarr/Models/NewSeries.cs b/src/Ombi.Api.Sonarr/Models/NewSeries.cs
index 4d2c17308..d6f721b0b 100644
--- a/src/Ombi.Api.Sonarr/Models/NewSeries.cs
+++ b/src/Ombi.Api.Sonarr/Models/NewSeries.cs
@@ -23,9 +23,13 @@ namespace Ombi.Api.Sonarr.Models
public string cleanTitle { get; set; }
public string imdbId { get; set; }
public string titleSlug { get; set; }
+ public string seriesType { get; set; }
public int id { get; set; }
public List images { get; set; }
+ // V3 Property
+ public int languageProfileId { get; set; }
+
///
/// This is for us
///
diff --git a/src/Ombi.Api.Sonarr/Models/Quality.cs b/src/Ombi.Api.Sonarr/Models/Quality.cs
index 76a1c92d8..9989a9c3e 100644
--- a/src/Ombi.Api.Sonarr/Models/Quality.cs
+++ b/src/Ombi.Api.Sonarr/Models/Quality.cs
@@ -2,6 +2,16 @@ namespace Ombi.Api.Sonarr.Models
{
public class Quality
{
+ public Quality()
+ {
+
+ }
+
+ public Quality(Quality q)
+ {
+ id = q.id;
+ name = q.name;
+ }
public int id { get; set; }
public string name { get; set; }
}
diff --git a/src/Ombi.Api.Sonarr/Models/SonarrSeries.cs b/src/Ombi.Api.Sonarr/Models/SonarrSeries.cs
index 568592734..3ade006d5 100644
--- a/src/Ombi.Api.Sonarr/Models/SonarrSeries.cs
+++ b/src/Ombi.Api.Sonarr/Models/SonarrSeries.cs
@@ -44,6 +44,7 @@ namespace Ombi.Api.Sonarr.Models
public DateTime added { get; set; }
public Ratings ratings { get; set; }
public int qualityProfileId { get; set; }
+ public int languageProfileId { get; set; }
public int id { get; set; }
public DateTime nextAiring { get; set; }
}
diff --git a/src/Ombi.Api.Sonarr/Models/V3/LanguageProfiles.cs b/src/Ombi.Api.Sonarr/Models/V3/LanguageProfiles.cs
new file mode 100644
index 000000000..aa3b199bd
--- /dev/null
+++ b/src/Ombi.Api.Sonarr/Models/V3/LanguageProfiles.cs
@@ -0,0 +1,30 @@
+namespace Ombi.Api.Sonarr.Models.V3
+{
+ public class LanguageProfiles
+ {
+ public string name { get; set; }
+ public bool upgradeAllowed { get; set; }
+ public Cutoff cutoff { get; set; }
+ public Languages[] languages { get; set; }
+ public int id { get; set; }
+ }
+
+ public class Cutoff
+ {
+ public int id { get; set; }
+ public string name { get; set; }
+ }
+
+ public class Languages
+ {
+ public Language languages { get; set; }
+ public bool allowed { get; set; }
+ }
+
+ public class Language
+ {
+ public int id { get; set; }
+ public string name { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/src/Ombi.Api.Sonarr/SonarrApi.cs b/src/Ombi.Api.Sonarr/SonarrApi.cs
index 7fd74d2a3..0b0df4c15 100644
--- a/src/Ombi.Api.Sonarr/SonarrApi.cs
+++ b/src/Ombi.Api.Sonarr/SonarrApi.cs
@@ -16,18 +16,19 @@ namespace Ombi.Api.Sonarr
Api = api;
}
- private IApi Api { get; }
+ protected IApi Api { get; }
+ protected virtual string ApiBaseUrl => "/api/";
public async Task> GetProfiles(string apiKey, string baseUrl)
{
- var request = new Request("/api/profile", baseUrl, HttpMethod.Get);
+ var request = new Request($"{ApiBaseUrl}profile", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
return await Api.Request
>(request);
}
public async Task> GetRootFolders(string apiKey, string baseUrl)
{
- var request = new Request("/api/rootfolder", baseUrl, HttpMethod.Get);
+ var request = new Request($"{ApiBaseUrl}rootfolder", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
return await Api.Request>(request);
}
@@ -40,7 +41,7 @@ namespace Ombi.Api.Sonarr
///
public async Task> GetSeries(string apiKey, string baseUrl)
{
- var request = new Request("/api/series", baseUrl, HttpMethod.Get);
+ var request = new Request($"{ApiBaseUrl}series", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
var results = await Api.Request>(request);
@@ -63,7 +64,7 @@ namespace Ombi.Api.Sonarr
///
public async Task GetSeriesById(int id, string apiKey, string baseUrl)
{
- var request = new Request($"/api/series/{id}", baseUrl, HttpMethod.Get);
+ var request = new Request($"{ApiBaseUrl}series/{id}", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
var result = await Api.Request(request);
if (result?.seasons?.Length > 0)
@@ -82,7 +83,7 @@ namespace Ombi.Api.Sonarr
///
public async Task UpdateSeries(SonarrSeries updated, string apiKey, string baseUrl)
{
- var request = new Request("/api/series/", baseUrl, HttpMethod.Put);
+ var request = new Request($"{ApiBaseUrl}series/", baseUrl, HttpMethod.Put);
request.AddHeader("X-Api-Key", apiKey);
request.AddJsonBody(updated);
return await Api.Request(request);
@@ -94,7 +95,7 @@ namespace Ombi.Api.Sonarr
{
return new NewSeries { ErrorMessages = new List { seriesToAdd.Validate() } };
}
- var request = new Request("/api/series/", baseUrl, HttpMethod.Post);
+ var request = new Request($"{ApiBaseUrl}series/", baseUrl, HttpMethod.Post);
request.AddHeader("X-Api-Key", apiKey);
request.AddJsonBody(seriesToAdd);
@@ -120,7 +121,7 @@ namespace Ombi.Api.Sonarr
///
public async Task> GetEpisodes(int seriesId, string apiKey, string baseUrl)
{
- var request = new Request($"/api/Episode?seriesId={seriesId}", baseUrl, HttpMethod.Get);
+ var request = new Request($"{ApiBaseUrl}Episode?seriesId={seriesId}", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
return await Api.Request>(request);
}
@@ -134,14 +135,14 @@ namespace Ombi.Api.Sonarr
///
public async Task GetEpisodeById(int episodeId, string apiKey, string baseUrl)
{
- var request = new Request($"/api/Episode/{episodeId}", baseUrl, HttpMethod.Get);
+ var request = new Request($"{ApiBaseUrl}Episode/{episodeId}", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
return await Api.Request(request);
}
public async Task UpdateEpisode(Episode episodeToUpdate, string apiKey, string baseUrl)
{
- var request = new Request($"/api/Episode/", baseUrl, HttpMethod.Put);
+ var request = new Request($"{ApiBaseUrl}Episode/", baseUrl, HttpMethod.Put);
request.AddHeader("X-Api-Key", apiKey);
request.AddJsonBody(episodeToUpdate);
return await Api.Request(request);
@@ -189,7 +190,7 @@ namespace Ombi.Api.Sonarr
private async Task Command(string apiKey, string baseUrl, object body)
{
- var request = new Request($"/api/Command/", baseUrl, HttpMethod.Post);
+ var request = new Request($"{ApiBaseUrl}Command/", baseUrl, HttpMethod.Post);
request.AddHeader("X-Api-Key", apiKey);
request.AddJsonBody(body);
return await Api.Request(request);
@@ -197,7 +198,7 @@ namespace Ombi.Api.Sonarr
public async Task SystemStatus(string apiKey, string baseUrl)
{
- var request = new Request("/api/system/status", baseUrl, HttpMethod.Get);
+ var request = new Request($"{ApiBaseUrl}system/status", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
return await Api.Request(request);
@@ -217,7 +218,7 @@ namespace Ombi.Api.Sonarr
ignoreEpisodesWithoutFiles = false,
}
};
- var request = new Request("/api/seasonpass", baseUrl, HttpMethod.Post);
+ var request = new Request($"{ApiBaseUrl}seasonpass", baseUrl, HttpMethod.Post);
request.AddHeader("X-Api-Key", apiKey);
request.AddJsonBody(seasonPass);
diff --git a/src/Ombi.Api.Sonarr/SonarrV3Api.cs b/src/Ombi.Api.Sonarr/SonarrV3Api.cs
new file mode 100644
index 000000000..64377ee4a
--- /dev/null
+++ b/src/Ombi.Api.Sonarr/SonarrV3Api.cs
@@ -0,0 +1,25 @@
+using System.Net.Http;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Ombi.Api.Sonarr.Models.V3;
+
+namespace Ombi.Api.Sonarr
+{
+ public class SonarrV3Api : SonarrApi, ISonarrV3Api
+ {
+ public SonarrV3Api(IApi api) : base(api)
+ {
+
+ }
+
+ protected override string ApiBaseUrl => "/api/v3/";
+
+ public async Task> LanguageProfiles(string apiKey, string baseUrl)
+ {
+ var request = new Request($"{ApiBaseUrl}languageprofile", baseUrl, HttpMethod.Get);
+ request.AddHeader("X-Api-Key", apiKey);
+
+ return await Api.Request>(request);
+ }
+ }
+}
diff --git a/src/Ombi.Api/Api.cs b/src/Ombi.Api/Api.cs
index b0e7066a8..8748530ec 100644
--- a/src/Ombi.Api/Api.cs
+++ b/src/Ombi.Api/Api.cs
@@ -41,7 +41,7 @@ namespace Ombi.Api
{
if (!request.IgnoreErrors)
{
- LogError(request, httpResponseMessage);
+ await LogError(request, httpResponseMessage);
}
if (request.Retry)
@@ -72,6 +72,7 @@ namespace Ombi.Api
// do something with the response
var receivedString = await httpResponseMessage.Content.ReadAsStringAsync();
+ LogDebugContent(receivedString);
if (request.ContentType == ContentType.Json)
{
request.OnBeforeDeserialization?.Invoke(receivedString);
@@ -80,15 +81,20 @@ namespace Ombi.Api
else
{
// XML
- XmlSerializer serializer = new XmlSerializer(typeof(T));
- StringReader reader = new StringReader(receivedString);
- var value = (T)serializer.Deserialize(reader);
- return value;
+ return DeserializeXml(receivedString);
}
}
}
+ public T DeserializeXml(string receivedString)
+ {
+ XmlSerializer serializer = new XmlSerializer(typeof(T));
+ StringReader reader = new StringReader(receivedString);
+ var value = (T) serializer.Deserialize(reader);
+ return value;
+ }
+
public async Task RequestContent(Request request)
{
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))
@@ -100,12 +106,12 @@ namespace Ombi.Api
{
if (!request.IgnoreErrors)
{
- LogError(request, httpResponseMessage);
+ await LogError(request, httpResponseMessage);
}
}
// do something with the response
var data = httpResponseMessage.Content;
-
+ await LogDebugContent(httpResponseMessage);
return await data.ReadAsStringAsync();
}
@@ -117,21 +123,23 @@ namespace Ombi.Api
{
AddHeadersBody(request, httpRequestMessage);
var httpResponseMessage = await _client.SendAsync(httpRequestMessage);
+ await LogDebugContent(httpResponseMessage);
if (!httpResponseMessage.IsSuccessStatusCode)
{
if (!request.IgnoreErrors)
{
- LogError(request, httpResponseMessage);
+ await LogError(request, httpResponseMessage);
}
}
}
}
- private static void AddHeadersBody(Request request, HttpRequestMessage httpRequestMessage)
+ private void AddHeadersBody(Request request, HttpRequestMessage httpRequestMessage)
{
// Add the Json Body
if (request.JsonBody != null)
{
+ LogDebugContent("REQUEST: " + request.JsonBody);
httpRequestMessage.Content = new JsonContent(request.JsonBody);
httpRequestMessage.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/json"); // Emby connect fails if we have the charset in the header
@@ -144,10 +152,28 @@ namespace Ombi.Api
}
}
- private void LogError(Request request, HttpResponseMessage httpResponseMessage)
+ private async Task LogError(Request request, HttpResponseMessage httpResponseMessage)
{
Logger.LogError(LoggingEvents.Api,
$"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}, RequestUri: {request.FullUri}");
+ await LogDebugContent(httpResponseMessage);
+ }
+
+ private async Task LogDebugContent(HttpResponseMessage message)
+ {
+ if (Logger.IsEnabled(LogLevel.Debug))
+ {
+ var content = await message.Content.ReadAsStringAsync();
+ Logger.LogDebug(content);
+ }
+ }
+
+ private void LogDebugContent(string message)
+ {
+ if (Logger.IsEnabled(LogLevel.Debug))
+ {
+ Logger.LogDebug(message);
+ }
}
}
}
diff --git a/src/Ombi.Api/HttpRequestExtnesions.cs b/src/Ombi.Api/HttpRequestExtensions.cs
similarity index 100%
rename from src/Ombi.Api/HttpRequestExtnesions.cs
rename to src/Ombi.Api/HttpRequestExtensions.cs
diff --git a/src/Ombi.Api/IApi.cs b/src/Ombi.Api/IApi.cs
index 2b7f71bb8..e573d2d07 100644
--- a/src/Ombi.Api/IApi.cs
+++ b/src/Ombi.Api/IApi.cs
@@ -7,5 +7,6 @@ namespace Ombi.Api
Task Request(Request request);
Task Request(Request request);
Task RequestContent(Request request);
+ T DeserializeXml(string receivedString);
}
}
\ No newline at end of file
diff --git a/src/Ombi.Api/Ombi.Api.csproj b/src/Ombi.Api/Ombi.Api.csproj
index a37c128fb..c7b905522 100644
--- a/src/Ombi.Api/Ombi.Api.csproj
+++ b/src/Ombi.Api/Ombi.Api.csproj
@@ -9,9 +9,9 @@
-
-
-
+
+
+
diff --git a/src/Ombi.Api/Request.cs b/src/Ombi.Api/Request.cs
index cfd284f54..fd888d0d2 100644
--- a/src/Ombi.Api/Request.cs
+++ b/src/Ombi.Api/Request.cs
@@ -28,6 +28,7 @@ namespace Ombi.Api
public bool IgnoreErrors { get; set; }
public bool Retry { get; set; }
public List StatusCodeToRetry { get; set; } = new List();
+ public bool IgnoreBaseUrlAppend { get; set; }
public Action OnBeforeDeserialization { get; set; }
@@ -38,7 +39,7 @@ namespace Ombi.Api
var sb = new StringBuilder();
if (!string.IsNullOrEmpty(BaseUrl))
{
- sb.Append(!BaseUrl.EndsWith("/") ? string.Format("{0}/", BaseUrl) : BaseUrl);
+ sb.Append(!BaseUrl.EndsWith("/") && !IgnoreBaseUrlAppend ? string.Format("{0}/", BaseUrl) : BaseUrl);
}
sb.Append(Endpoint.StartsWith("/") ? Endpoint.Remove(0, 1) : Endpoint);
return sb.ToString();
diff --git a/src/Ombi.Core.Tests/Engine/VoteEngineTests.cs b/src/Ombi.Core.Tests/Engine/VoteEngineTests.cs
new file mode 100644
index 000000000..ad4c33131
--- /dev/null
+++ b/src/Ombi.Core.Tests/Engine/VoteEngineTests.cs
@@ -0,0 +1,73 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Principal;
+using System.Threading.Tasks;
+using AutoFixture;
+using Moq;
+using NUnit.Framework;
+using Ombi.Core.Authentication;
+using Ombi.Core.Engine;
+using Ombi.Core.Engine.Interfaces;
+using Ombi.Core.Rule.Interfaces;
+using Ombi.Core.Settings;
+using Ombi.Settings.Settings.Models;
+using Ombi.Store.Entities;
+using Ombi.Store.Repository;
+
+namespace Ombi.Core.Tests.Engine
+{
+ [TestFixture]
+ public class VoteEngineTests
+ {
+ [SetUp]
+ public void Setup()
+ {
+ F = new Fixture();
+ VoteRepository = new Mock>();
+ VoteSettings = new Mock>();
+ MusicRequestEngine = new Mock();
+ TvRequestEngine = new Mock();
+ MovieRequestEngine = new Mock();
+ MovieRequestEngine = new Mock();
+ User = new Mock();
+ UserManager = new Mock();
+ UserManager.Setup(x => x.Users)
+ .Returns(new EnumerableQuery(new List {new OmbiUser {Id = "abc"}}));
+ Rule = new Mock();
+ Engine = new VoteEngine(VoteRepository.Object, User.Object, UserManager.Object, Rule.Object, VoteSettings.Object, MusicRequestEngine.Object,
+ TvRequestEngine.Object, MovieRequestEngine.Object);
+ }
+
+ public Fixture F { get; set; }
+ public VoteEngine Engine { get; set; }
+ public Mock User { get; set; }
+ public Mock UserManager { get; set; }
+ public Mock Rule { get; set; }
+ public Mock> VoteRepository { get; set; }
+ public Mock> VoteSettings { get; set; }
+ public Mock MusicRequestEngine { get; set; }
+ public Mock TvRequestEngine { get; set; }
+ public Mock MovieRequestEngine { get; set; }
+
+ [Test]
+ [Ignore("Need to mock the user manager")]
+ public async Task New_Upvote()
+ {
+ VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings());
+ var votes = F.CreateMany().ToList();
+ votes.Add(new Votes
+ {
+ RequestId = 1,
+ RequestType = RequestType.Movie,
+ UserId = "abc"
+ });
+ VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery(votes));
+ var result = await Engine.UpVote(1, RequestType.Movie);
+
+ Assert.That(result.Result, Is.True);
+ VoteRepository.Verify(x => x.Add(It.Is(c => c.UserId == "abc" && c.VoteType == VoteType.Upvote)), Times.Once);
+ VoteRepository.Verify(x => x.Delete(It.IsAny()), Times.Once);
+ MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj b/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj
index 8f0abee8f..23fc6db78 100644
--- a/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj
+++ b/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj
@@ -1,15 +1,16 @@
- netcoreapp2.1
+ netcoreapp2.2
-
-
-
-
-
+
+
+
+
+
+
diff --git a/src/Ombi.Core.Tests/Rule/Request/AutoApproveRuleTests.cs b/src/Ombi.Core.Tests/Rule/Request/AutoApproveRuleTests.cs
index 7ff8283da..34c21e008 100644
--- a/src/Ombi.Core.Tests/Rule/Request/AutoApproveRuleTests.cs
+++ b/src/Ombi.Core.Tests/Rule/Request/AutoApproveRuleTests.cs
@@ -4,6 +4,7 @@ using Moq;
using Ombi.Core.Rule.Rules.Request;
using Ombi.Store.Entities.Requests;
using NUnit.Framework;
+using Ombi.Core.Authentication;
using Ombi.Helpers;
namespace Ombi.Core.Tests.Rule.Request
@@ -16,7 +17,7 @@ namespace Ombi.Core.Tests.Rule.Request
{
PrincipalMock = new Mock();
- Rule = new AutoApproveRule(PrincipalMock.Object);
+ Rule = new AutoApproveRule(PrincipalMock.Object, null);
}
diff --git a/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs b/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs
index c9db5875a..f2781c8d2 100644
--- a/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs
+++ b/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using Ombi.Core.Rule.Rules;
+using Ombi.Core.Rule.Rules.Request;
using Ombi.Helpers;
using Ombi.Store.Entities.Requests;
@@ -15,7 +16,7 @@ namespace Ombi.Core.Tests.Rule.Request
{
PrincipalMock = new Mock();
- Rule = new CanRequestRule(PrincipalMock.Object);
+ Rule = new CanRequestRule(PrincipalMock.Object, null);
}
diff --git a/src/Ombi.Core.Tests/Rule/Search/CouchPotatoCacheRuleTests.cs b/src/Ombi.Core.Tests/Rule/Search/CouchPotatoCacheRuleTests.cs
index 56524522b..2a8f7a520 100644
--- a/src/Ombi.Core.Tests/Rule/Search/CouchPotatoCacheRuleTests.cs
+++ b/src/Ombi.Core.Tests/Rule/Search/CouchPotatoCacheRuleTests.cs
@@ -18,13 +18,13 @@ namespace Ombi.Core.Tests.Rule.Search
[SetUp]
public void Setup()
{
- ContextMock = new Mock>();
+ ContextMock = new Mock>();
Rule = new CouchPotatoCacheRule(ContextMock.Object);
}
private CouchPotatoCacheRule Rule { get; set; }
- private Mock> ContextMock { get; set; }
+ private Mock> ContextMock { get; set; }
[Test]
public async Task Should_ReturnApproved_WhenMovieIsInCouchPotato()
diff --git a/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs b/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs
index 0633d641e..0171e37a1 100644
--- a/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs
+++ b/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs
@@ -16,7 +16,7 @@ namespace Ombi.Core.Tests.Rule.Search
public void Setup()
{
ContextMock = new Mock();
- Rule = new EmbyAvailabilityRule(ContextMock.Object);
+ Rule = new EmbyAvailabilityRule(ContextMock.Object, null);
}
private EmbyAvailabilityRule Rule { get; set; }
@@ -29,7 +29,10 @@ namespace Ombi.Core.Tests.Rule.Search
{
ProviderId = "123"
});
- var search = new SearchMovieViewModel();
+ var search = new SearchMovieViewModel()
+ {
+ TheMovieDbId = "123",
+ };
var result = await Rule.Execute(search);
Assert.True(result.Success);
diff --git a/src/Ombi.Core.Tests/Rule/Search/ExistingRequestRuleTests.cs b/src/Ombi.Core.Tests/Rule/Search/ExistingRequestRuleTests.cs
index a706472dd..e32c8e996 100644
--- a/src/Ombi.Core.Tests/Rule/Search/ExistingRequestRuleTests.cs
+++ b/src/Ombi.Core.Tests/Rule/Search/ExistingRequestRuleTests.cs
@@ -19,12 +19,14 @@ namespace Ombi.Core.Tests.Rule.Search
MovieMock = new Mock();
TvMock = new Mock();
- Rule = new ExistingRule(MovieMock.Object, TvMock.Object);
+ MusicMock = new Mock();
+ Rule = new ExistingRule(MovieMock.Object, TvMock.Object, MusicMock.Object);
}
private ExistingRule Rule { get; set; }
private Mock MovieMock { get; set; }
private Mock TvMock { get; set; }
+ private Mock MusicMock { get; set; }
[Test]
diff --git a/src/Ombi.Core.Tests/Rule/Search/PlexAvailabilityRuleTests.cs b/src/Ombi.Core.Tests/Rule/Search/PlexAvailabilityRuleTests.cs
index 55177a6ac..5bd35473c 100644
--- a/src/Ombi.Core.Tests/Rule/Search/PlexAvailabilityRuleTests.cs
+++ b/src/Ombi.Core.Tests/Rule/Search/PlexAvailabilityRuleTests.cs
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Ombi.Core.Models.Search;
@@ -14,7 +15,7 @@ namespace Ombi.Core.Tests.Rule.Search
public void Setup()
{
ContextMock = new Mock();
- Rule = new PlexAvailabilityRule(ContextMock.Object);
+ Rule = new PlexAvailabilityRule(ContextMock.Object, new Mock>().Object);
}
private PlexAvailabilityRule Rule { get; set; }
diff --git a/src/Ombi.Core.Tests/Rule/Search/RadarrCacheRuleTests.cs b/src/Ombi.Core.Tests/Rule/Search/RadarrCacheRuleTests.cs
index 914112d5b..94efe89a2 100644
--- a/src/Ombi.Core.Tests/Rule/Search/RadarrCacheRuleTests.cs
+++ b/src/Ombi.Core.Tests/Rule/Search/RadarrCacheRuleTests.cs
@@ -15,13 +15,13 @@ namespace Ombi.Core.Tests.Rule.Search
[SetUp]
public void Setup()
{
- ContextMock = new Mock>();
+ ContextMock = new Mock>();
Rule = new RadarrCacheRule(ContextMock.Object);
}
private RadarrCacheRule Rule { get; set; }
- private Mock> ContextMock { get; set; }
+ private Mock> ContextMock { get; set; }
[Test]
public async Task Should_ReturnApproved_WhenMovieIsInRadarr()
diff --git a/src/Ombi.Core.Tests/StringHelperTests.cs b/src/Ombi.Core.Tests/StringHelperTests.cs
new file mode 100644
index 000000000..c1b95fcd7
--- /dev/null
+++ b/src/Ombi.Core.Tests/StringHelperTests.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+using NUnit.Framework;
+using Ombi.Helpers;
+
+namespace Ombi.Core.Tests
+{
+ [TestFixture]
+ public class StringHelperTests
+ {
+ [TestCaseSource(nameof(StripCharsData))]
+ public string StripCharacters(string str, char[] chars)
+ {
+ return str.StripCharacters(chars);
+ }
+
+ private static IEnumerable StripCharsData
+ {
+ get
+ {
+ yield return new TestCaseData("this!is^a*string",new []{'!','^','*'}).Returns("thisisastring").SetName("Basic Strip Multipe Chars");
+ yield return new TestCaseData("What is this madness'",new []{'\'','^','*'}).Returns("What is this madness").SetName("Basic Strip Multipe Chars");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Core/Authentication/OmbiUserManager.cs b/src/Ombi.Core/Authentication/OmbiUserManager.cs
index 185677215..2c78f39bf 100644
--- a/src/Ombi.Core/Authentication/OmbiUserManager.cs
+++ b/src/Ombi.Core/Authentication/OmbiUserManager.cs
@@ -29,6 +29,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Ombi.Api.Emby;
@@ -101,6 +102,22 @@ namespace Ombi.Core.Authentication
return true;
}
+ public async Task GetOmbiUserFromPlexToken(string plexToken)
+ {
+ var plexAccount = await _plexApi.GetAccount(plexToken);
+
+ // Check for a ombi user
+ if (plexAccount?.user != null)
+ {
+ var potentialOmbiUser = await Users.FirstOrDefaultAsync(x =>
+ x.ProviderUserId == plexAccount.user.id);
+ return potentialOmbiUser;
+ }
+
+ return null;
+ }
+
+
///
/// Sign the user into plex and make sure we can get the authentication token.
/// We do not check if the user is in the owners "friends" since they must have a local user account to get this far
diff --git a/src/Ombi.Core/Authentication/PlexOAuthManager.cs b/src/Ombi.Core/Authentication/PlexOAuthManager.cs
index 803176d74..76b1b5d97 100644
--- a/src/Ombi.Core/Authentication/PlexOAuthManager.cs
+++ b/src/Ombi.Core/Authentication/PlexOAuthManager.cs
@@ -28,19 +28,6 @@ namespace Ombi.Core.Authentication
return string.Empty;
}
- if (pin.authToken.IsNullOrEmpty())
- {
- // Looks like we do not have a pin yet, we should retry a few times.
- var retryCount = 0;
- var retryMax = 5;
- var retryWaitMs = 1000;
- while (pin.authToken.IsNullOrEmpty() && retryCount < retryMax)
- {
- retryCount++;
- await Task.Delay(retryWaitMs);
- pin = await _api.GetPin(pinId);
- }
- }
return pin.authToken;
}
@@ -49,17 +36,17 @@ namespace Ombi.Core.Authentication
return await _api.GetAccount(accessToken);
}
- public async Task GetOAuthUrl(int pinId, string code, string websiteAddress = null)
+ public async Task GetOAuthUrl(string code, string websiteAddress = null)
{
var settings = await _customizationSettingsService.GetSettingsAsync();
- var url = await _api.GetOAuthUrl(pinId, code, settings.ApplicationUrl.IsNullOrEmpty() ? websiteAddress : settings.ApplicationUrl, false);
+ var url = await _api.GetOAuthUrl(code, settings.ApplicationUrl.IsNullOrEmpty() ? websiteAddress : settings.ApplicationUrl);
return url;
}
- public async Task GetWizardOAuthUrl(int pinId, string code, string websiteAddress)
+ public async Task GetWizardOAuthUrl(string code, string websiteAddress)
{
- var url = await _api.GetOAuthUrl(pinId, code, websiteAddress, true);
+ var url = await _api.GetOAuthUrl(code, websiteAddress);
return url;
}
}
diff --git a/src/Ombi.Core/Engine/BaseMediaEngine.cs b/src/Ombi.Core/Engine/BaseMediaEngine.cs
index 2eab74b75..d0bb74c91 100644
--- a/src/Ombi.Core/Engine/BaseMediaEngine.cs
+++ b/src/Ombi.Core/Engine/BaseMediaEngine.cs
@@ -36,6 +36,7 @@ namespace Ombi.Core.Engine
protected IRequestServiceMain RequestService { get; }
protected IMovieRequestRepository MovieRepository => RequestService.MovieRequestService;
protected ITvRequestRepository TvRepository => RequestService.TvRequestService;
+ protected IMusicRequestRepository MusicRepository => RequestService.MusicRequestRepository;
protected readonly ICacheService Cache;
protected readonly ISettingsService OmbiSettings;
protected readonly IRepository _subscriptionRepository;
@@ -156,6 +157,24 @@ namespace Ombi.Core.Engine
}
}
+ private string defaultLangCode;
+ protected async Task DefaultLanguageCode(string currentCode)
+ {
+ if (currentCode.HasValue())
+ {
+ return currentCode;
+ }
+
+ var s = await GetOmbiSettings();
+ return s.DefaultLanguageCode;
+ }
+
+ private OmbiSettings ombiSettings;
+ protected async Task GetOmbiSettings()
+ {
+ return ombiSettings ?? (ombiSettings = await OmbiSettings.GetSettingsAsync());
+ }
+
public class HideResult
{
public bool Hide { get; set; }
diff --git a/src/Ombi.Core/Engine/Demo/DemoMovieSearchEngine.cs b/src/Ombi.Core/Engine/Demo/DemoMovieSearchEngine.cs
new file mode 100644
index 000000000..86582fb4d
--- /dev/null
+++ b/src/Ombi.Core/Engine/Demo/DemoMovieSearchEngine.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Principal;
+using System.Text;
+using System.Threading.Tasks;
+using AutoMapper;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Ombi.Api.TheMovieDb;
+using Ombi.Api.TheMovieDb.Models;
+using Ombi.Config;
+using Ombi.Core.Authentication;
+using Ombi.Core.Models.Requests;
+using Ombi.Core.Models.Search;
+using Ombi.Core.Rule.Interfaces;
+using Ombi.Core.Settings;
+using Ombi.Helpers;
+using Ombi.Settings.Settings.Models;
+using Ombi.Store.Entities;
+using Ombi.Store.Repository;
+
+namespace Ombi.Core.Engine.Demo
+{
+ public class DemoMovieSearchEngine : MovieSearchEngine, IDemoMovieSearchEngine
+ {
+ public DemoMovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
+ ILogger logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService s,
+ IRepository sub, IOptions lists)
+ : base(identity, service, movApi, mapper, logger, r, um, mem, s, sub)
+ {
+ _demoLists = lists.Value;
+ }
+
+ private readonly DemoLists _demoLists;
+
+ public async Task> Search(string search)
+ {
+ var result = await MovieApi.SearchMovie(search, null, "en");
+
+ for (var i = 0; i < result.Count; i++)
+ {
+ if (!_demoLists.Movies.Contains(result[i].Id))
+ {
+ result.RemoveAt(i);
+ }
+ }
+ if(result.Count > 0)
+ return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API
+ return null;
+ }
+
+ public async Task> NowPlayingMovies()
+ {
+ var rand = new Random();
+ var responses = new List();
+ for (int i = 0; i < 10; i++)
+ {
+ var item = rand.Next(_demoLists.Movies.Length);
+ var movie = _demoLists.Movies[item];
+ if (responses.Any(x => x.Id == movie))
+ {
+ i--;
+ continue;
+ }
+ var movieResult = await MovieApi.GetMovieInformationWithExtraInfo(movie);
+ var viewMovie = Mapper.Map(movieResult);
+
+ responses.Add(await ProcessSingleMovie(viewMovie));
+ }
+
+ return responses;
+ }
+
+ public async Task> PopularMovies()
+ {
+ return await NowPlayingMovies();
+ }
+
+
+ public async Task> TopRatedMovies()
+ {
+ return await NowPlayingMovies();
+ }
+
+ public async Task> UpcomingMovies()
+ {
+
+ return await NowPlayingMovies();
+ }
+ }
+
+ public interface IDemoMovieSearchEngine
+ {
+ Task> NowPlayingMovies();
+
+ Task> PopularMovies();
+
+ Task> Search(string search);
+
+ Task> TopRatedMovies();
+
+ Task> UpcomingMovies();
+
+ }
+}
diff --git a/src/Ombi.Core/Engine/Demo/DemoTvSearchEngine.cs b/src/Ombi.Core/Engine/Demo/DemoTvSearchEngine.cs
new file mode 100644
index 000000000..edf9c430d
--- /dev/null
+++ b/src/Ombi.Core/Engine/Demo/DemoTvSearchEngine.cs
@@ -0,0 +1,96 @@
+using AutoMapper;
+using Microsoft.Extensions.Options;
+using Ombi.Api.Trakt;
+using Ombi.Api.TvMaze;
+using Ombi.Config;
+using Ombi.Core.Authentication;
+using Ombi.Core.Models.Requests;
+using Ombi.Core.Models.Search;
+using Ombi.Core.Rule.Interfaces;
+using Ombi.Core.Settings;
+using Ombi.Core.Settings.Models.External;
+using Ombi.Helpers;
+using Ombi.Settings.Settings.Models;
+using Ombi.Store.Entities;
+using Ombi.Store.Repository;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Principal;
+using System.Threading.Tasks;
+
+namespace Ombi.Core.Engine.Demo
+{
+ public class DemoTvSearchEngine : TvSearchEngine, IDemoTvSearchEngine
+ {
+
+ public DemoTvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
+ ISettingsService plexSettings, ISettingsService embySettings, IPlexContentRepository repo,
+ IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache,
+ ISettingsService s, IRepository sub, IOptions lists)
+ : base(identity, service, tvMaze, mapper, plexSettings, embySettings, repo, embyRepo, trakt, r, um, memCache, s, sub)
+ {
+ _demoLists = lists.Value;
+ }
+
+ private readonly DemoLists _demoLists;
+
+ public async Task> Search(string search)
+ {
+ var searchResult = await TvMazeApi.Search(search);
+
+ for (var i = 0; i < searchResult.Count; i++)
+ {
+ if (!_demoLists.TvShows.Contains(searchResult[i].show?.externals?.thetvdb ?? 0))
+ {
+ searchResult.RemoveAt(i);
+ }
+ }
+
+ if (searchResult != null)
+ {
+ var retVal = new List();
+ foreach (var tvMazeSearch in searchResult)
+ {
+ if (tvMazeSearch.show.externals == null || !(tvMazeSearch.show.externals?.thetvdb.HasValue ?? false))
+ {
+ continue;
+ }
+ retVal.Add(ProcessResult(tvMazeSearch));
+ }
+ return retVal;
+ }
+ return null;
+ }
+
+ public async Task> NowPlayingMovies()
+ {
+ var rand = new Random();
+ var responses = new List();
+ for (int i = 0; i < 10; i++)
+ {
+ var item = rand.Next(_demoLists.TvShows.Length);
+ var tv = _demoLists.TvShows[item];
+ if (responses.Any(x => x.Id == tv))
+ {
+ i--;
+ continue;
+ }
+
+ var movieResult = await TvMazeApi.ShowLookup(tv);
+ responses.Add(ProcessResult(movieResult));
+ }
+
+ return responses;
+ }
+
+
+
+ }
+
+ public interface IDemoTvSearchEngine
+ {
+ Task> Search(string search);
+ Task> NowPlayingMovies();
+ }
+}
diff --git a/src/Ombi.Core/Engine/IMusicRequestEngine.cs b/src/Ombi.Core/Engine/IMusicRequestEngine.cs
new file mode 100644
index 000000000..02a051343
--- /dev/null
+++ b/src/Ombi.Core/Engine/IMusicRequestEngine.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Ombi.Core.Models;
+using Ombi.Core.Models.Requests;
+using Ombi.Core.Models.UI;
+using Ombi.Store.Entities;
+using Ombi.Store.Entities.Requests;
+
+namespace Ombi.Core.Engine
+{
+ public interface IMusicRequestEngine
+ {
+ TaskApproveAlbum(AlbumRequest request);
+ Task ApproveAlbumById(int requestId);
+ Task DenyAlbumById(int modelId, string reason);
+ Task> GetRequests();
+ Task> GetRequests(int count, int position, OrderFilterModel orderFilter);
+ Task GetTotal();
+ Task MarkAvailable(int modelId);
+ Task MarkUnavailable(int modelId);
+ Task RemoveAlbumRequest(int requestId);
+ Task RequestAlbum(MusicAlbumRequestViewModel model);
+ Task> SearchAlbumRequest(string search);
+ Task UserHasRequest(string userId);
+ Task GetRemainingRequests(OmbiUser user = null);
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Core/Engine/IVoteEngine.cs b/src/Ombi.Core/Engine/IVoteEngine.cs
new file mode 100644
index 000000000..681f333c5
--- /dev/null
+++ b/src/Ombi.Core/Engine/IVoteEngine.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Ombi.Core.Models;
+using Ombi.Core.Models.UI;
+using Ombi.Store.Entities;
+
+namespace Ombi.Core.Engine
+{
+ public interface IVoteEngine
+ {
+ Task DownVote(int requestId, RequestType requestType);
+ Task GetVoteForUser(int requestId, string userId);
+ IQueryable GetVotes(int requestId, RequestType requestType);
+ Task RemoveCurrentVote(Votes currentVote);
+ Task UpVote(int requestId, RequestType requestType);
+ Task> GetMovieViewModel();
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Core/Engine/Interfaces/BaseEngine.cs b/src/Ombi.Core/Engine/Interfaces/BaseEngine.cs
index 26bc5969c..c5cb8c45a 100644
--- a/src/Ombi.Core/Engine/Interfaces/BaseEngine.cs
+++ b/src/Ombi.Core/Engine/Interfaces/BaseEngine.cs
@@ -7,11 +7,8 @@ using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces;
using Ombi.Store.Entities.Requests;
using Ombi.Store.Entities;
-using Microsoft.AspNetCore.Identity;
-using System.Linq;
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication;
-using Ombi.Helpers;
namespace Ombi.Core.Engine.Interfaces
{
diff --git a/src/Ombi.Core/Engine/Interfaces/IMovieEngine.cs b/src/Ombi.Core/Engine/Interfaces/IMovieEngine.cs
index 91b6404db..9b4cd9831 100644
--- a/src/Ombi.Core/Engine/Interfaces/IMovieEngine.cs
+++ b/src/Ombi.Core/Engine/Interfaces/IMovieEngine.cs
@@ -10,14 +10,15 @@ namespace Ombi.Core
Task> PopularMovies();
- Task> Search(string search);
+ Task> Search(string search, int? year, string languageCode);
Task> TopRatedMovies();
Task> UpcomingMovies();
- Task LookupImdbInformation(int theMovieDbId);
+ Task LookupImdbInformation(int theMovieDbId, string langCode = null);
- Task> SimilarMovies(int theMovieDbId);
+ Task> SimilarMovies(int theMovieDbId, string langCode);
+ Task