diff --git a/CHANGELOG.md b/CHANGELOG.md index debc40f62..0035180dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,148 @@ # Changelog + +## (unreleased) + +### **New Features** + +- 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] + ## v3.0.4036 (2018-12-11) +- Update EmbyEpisodeSync.cs. [Jamie] + +- Updated to .net core 2.2 and included a linux-arm64 build. [TidusJar] + +### **Fixes** + +- 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] @@ -37,8 +170,7 @@ ### **Fixes** - -- Fixed #2601 [TidusJar] +- !changelog. [Jamie] - Made the subscribe/unsubscribe button more obvious on the UI #2309. [Jamie] diff --git a/appveyor.yml b/appveyor.yml index 448e1b9c8..3c60a0006 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,22 +27,22 @@ 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/music-placeholder.psd b/assets/music-placeholder.psd similarity index 100% rename from music-placeholder.psd rename to assets/music-placeholder.psd diff --git a/build.cake b/build.cake index d706e7b6b..e8e4bb8c0 100644 --- a/build.cake +++ b/build.cake @@ -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 { @@ -151,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") @@ -227,7 +227,7 @@ 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); }); diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 10c7546e4..000000000 --- a/package-lock.json +++ /dev/null @@ -1,291 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "1.0.3" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - } - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "1.9.1" - } - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "requires": { - "has-flag": "3.0.0" - } - } - } - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "1.1.11" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" - }, - "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "requires": { - "path-parse": "1.0.5" - } - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, - "tslib": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.2.tgz", - "integrity": "sha512-AVP5Xol3WivEr7hnssHDsaM+lVrVXWUvd1cfXTRkTj80b//6g2wIFEH6hZG0muGZRnHGrfttpdzRk3YlBkWjKw==" - }, - "tslint": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.10.0.tgz", - "integrity": "sha1-EeJrzLiK+gLdDZlWyuPUVAtfVMM=", - "requires": { - "babel-code-frame": "6.26.0", - "builtin-modules": "1.1.1", - "chalk": "2.4.1", - "commander": "2.15.1", - "diff": "3.5.0", - "glob": "7.1.2", - "js-yaml": "3.12.0", - "minimatch": "3.0.4", - "resolve": "1.7.1", - "semver": "5.5.0", - "tslib": "1.9.2", - "tsutils": "2.27.1" - } - }, - "tsutils": { - "version": "2.27.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.27.1.tgz", - "integrity": "sha512-AE/7uzp32MmaHvNNFES85hhUDHFdFZp6OAiZcd6y4ZKKIg6orJTm8keYWBhIhrJQH3a4LzNKat7ZPXZt5aTf6w==", - "requires": { - "tslib": "1.9.2" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } - } -} 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.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.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/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/Ombi.Api.csproj b/src/Ombi.Api/Ombi.Api.csproj index a37c128fb..e20dd6ccd 100644 --- a/src/Ombi.Api/Ombi.Api.csproj +++ b/src/Ombi.Api/Ombi.Api.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj b/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj index d20176ec4..23fc6db78 100644 --- a/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj +++ b/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp2.1 + netcoreapp2.2 @@ -10,7 +10,7 @@ - + diff --git a/src/Ombi.Core/Engine/BaseMediaEngine.cs b/src/Ombi.Core/Engine/BaseMediaEngine.cs index cb0047b96..d0bb74c91 100644 --- a/src/Ombi.Core/Engine/BaseMediaEngine.cs +++ b/src/Ombi.Core/Engine/BaseMediaEngine.cs @@ -157,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/IMusicRequestEngine.cs b/src/Ombi.Core/Engine/IMusicRequestEngine.cs index 5caba8a34..02a051343 100644 --- a/src/Ombi.Core/Engine/IMusicRequestEngine.cs +++ b/src/Ombi.Core/Engine/IMusicRequestEngine.cs @@ -12,7 +12,7 @@ namespace Ombi.Core.Engine { TaskApproveAlbum(AlbumRequest request); Task ApproveAlbumById(int requestId); - Task DenyAlbumById(int modelId); + Task DenyAlbumById(int modelId, string reason); Task> GetRequests(); Task> GetRequests(int count, int position, OrderFilterModel orderFilter); Task GetTotal(); diff --git a/src/Ombi.Core/Engine/Interfaces/IMovieEngine.cs b/src/Ombi.Core/Engine/Interfaces/IMovieEngine.cs index 91b6404db..b80d132d1 100644 --- a/src/Ombi.Core/Engine/Interfaces/IMovieEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/IMovieEngine.cs @@ -10,14 +10,14 @@ 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); } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs b/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs index bb8b9e64d..d741dc8bc 100644 --- a/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs @@ -17,6 +17,6 @@ namespace Ombi.Core.Engine.Interfaces Task UpdateMovieRequest(MovieRequests request); Task ApproveMovie(MovieRequests request); Task ApproveMovieById(int requestId); - Task DenyMovieById(int modelId); + Task DenyMovieById(int modelId, string denyReason); } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/Interfaces/ITvRequestEngine.cs b/src/Ombi.Core/Engine/Interfaces/ITvRequestEngine.cs index 36ae7da61..63de72bd1 100644 --- a/src/Ombi.Core/Engine/Interfaces/ITvRequestEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/ITvRequestEngine.cs @@ -12,7 +12,7 @@ namespace Ombi.Core.Engine.Interfaces Task RemoveTvRequest(int requestId); Task GetTvRequest(int requestId); Task RequestTvShow(TvRequestViewModel tv); - Task DenyChildRequest(int requestId); + Task DenyChildRequest(int requestId, string reason); Task> GetRequestsLite(int count, int position, OrderFilterModel type); Task> SearchTvRequest(string search); Task UpdateTvRequest(TvRequests request); diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs index 16fd7667b..b584a4bed 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -51,7 +51,7 @@ namespace Ombi.Core.Engine /// public async Task RequestMovie(MovieRequestViewModel model) { - var movieInfo = await MovieApi.GetMovieInformationWithExtraInfo(model.TheMovieDbId); + var movieInfo = await MovieApi.GetMovieInformationWithExtraInfo(model.TheMovieDbId, model.LanguageCode); if (movieInfo == null || movieInfo.Id == 0) { return new RequestEngineResult @@ -82,7 +82,8 @@ namespace Ombi.Core.Engine RequestedDate = DateTime.UtcNow, Approved = false, RequestedUserId = userDetails.Id, - Background = movieInfo.BackdropPath + Background = movieInfo.BackdropPath, + LangCode = model.LanguageCode }; var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US"); @@ -305,7 +306,7 @@ namespace Ombi.Core.Engine return await ApproveMovie(request); } - public async Task DenyMovieById(int modelId) + public async Task DenyMovieById(int modelId, string denyReason) { var request = await MovieRepository.Find(modelId); if (request == null) @@ -317,6 +318,7 @@ namespace Ombi.Core.Engine } request.Denied = true; + request.DeniedReason = denyReason; // We are denying a request NotificationHelper.Notify(request, NotificationType.RequestDeclined); await MovieRepository.Update(request); diff --git a/src/Ombi.Core/Engine/MovieSearchEngine.cs b/src/Ombi.Core/Engine/MovieSearchEngine.cs index 09b4cea6b..5e56e8abd 100644 --- a/src/Ombi.Core/Engine/MovieSearchEngine.cs +++ b/src/Ombi.Core/Engine/MovieSearchEngine.cs @@ -1,23 +1,22 @@ -using System; -using AutoMapper; +using AutoMapper; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb.Models; +using Ombi.Core.Authentication; using Ombi.Core.Models.Requests; using Ombi.Core.Models.Search; -using System.Collections.Generic; -using System.Linq; -using System.Security.Principal; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; using Ombi.Core.Rule.Interfaces; -using Microsoft.Extensions.Caching.Memory; -using Ombi.Core.Authentication; using Ombi.Core.Settings; 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 { @@ -36,14 +35,17 @@ namespace Ombi.Core.Engine private IMapper Mapper { get; } private ILogger Logger { get; } + private const int MovieLimit = 10; + /// /// Lookups the imdb information. /// /// The movie database identifier. /// - public async Task LookupImdbInformation(int theMovieDbId) + public async Task LookupImdbInformation(int theMovieDbId, string langCode = null) { - var movieInfo = await MovieApi.GetMovieInformationWithExtraInfo(theMovieDbId); + langCode = await DefaultLanguageCode(langCode); + var movieInfo = await MovieApi.GetMovieInformationWithExtraInfo(theMovieDbId, langCode); var viewMovie = Mapper.Map(movieInfo); return await ProcessSingleMovie(viewMovie, true); @@ -54,13 +56,14 @@ namespace Ombi.Core.Engine /// /// The search. /// - public async Task> Search(string search) + public async Task> Search(string search, int? year, string langaugeCode) { - var result = await MovieApi.SearchMovie(search); + langaugeCode = await DefaultLanguageCode(langaugeCode); + var result = await MovieApi.SearchMovie(search, year, langaugeCode); if (result != null) { - return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API + return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API } return null; } @@ -70,13 +73,14 @@ namespace Ombi.Core.Engine /// /// /// - public async Task> SimilarMovies(int theMovieDbId) + public async Task> SimilarMovies(int theMovieDbId, string langCode) { - var result = await MovieApi.SimilarMovies(theMovieDbId); + langCode = await DefaultLanguageCode(langCode); + var result = await MovieApi.SimilarMovies(theMovieDbId, langCode); if (result != null) { Logger.LogDebug("Search Result: {result}", result); - return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API + return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API } return null; } @@ -87,10 +91,15 @@ namespace Ombi.Core.Engine /// public async Task> PopularMovies() { - var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () => await MovieApi.PopularMovies(), DateTime.Now.AddHours(12)); + + var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () => + { + var langCode = await DefaultLanguageCode(null); + return await MovieApi.PopularMovies(langCode); + }, DateTime.Now.AddHours(12)); if (result != null) { - return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API + return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API } return null; } @@ -101,10 +110,14 @@ namespace Ombi.Core.Engine /// public async Task> TopRatedMovies() { - var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () => await MovieApi.TopRated(), DateTime.Now.AddHours(12)); + var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () => + { + var langCode = await DefaultLanguageCode(null); + return await MovieApi.TopRated(langCode); + }, DateTime.Now.AddHours(12)); if (result != null) { - return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API + return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API } return null; } @@ -115,11 +128,15 @@ namespace Ombi.Core.Engine /// public async Task> UpcomingMovies() { - var result = await Cache.GetOrAdd(CacheKeys.UpcomingMovies, async () => await MovieApi.Upcoming(), DateTime.Now.AddHours(12)); + var result = await Cache.GetOrAdd(CacheKeys.UpcomingMovies, async () => + { + var langCode = await DefaultLanguageCode(null); + return await MovieApi.Upcoming(langCode); + }, DateTime.Now.AddHours(12)); if (result != null) { Logger.LogDebug("Search Result: {result}", result); - return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API + return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API } return null; } @@ -130,10 +147,14 @@ namespace Ombi.Core.Engine /// public async Task> NowPlayingMovies() { - var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () => await MovieApi.NowPlaying(), DateTime.Now.AddHours(12)); + var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () => + { + var langCode = await DefaultLanguageCode(null); + return await MovieApi.NowPlaying(langCode); + }, DateTime.Now.AddHours(12)); if (result != null) { - return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API + return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API } return null; } @@ -174,6 +195,10 @@ namespace Ombi.Core.Engine { // Check if this user requested it var user = await GetUser(); + if (user == null) + { + return; + } var request = await RequestService.MovieRequestService.GetAll() .AnyAsync(x => x.RequestedUserId.Equals(user.Id) && x.TheMovieDbId == viewModel.Id); if (request) diff --git a/src/Ombi.Core/Engine/MusicRequestEngine.cs b/src/Ombi.Core/Engine/MusicRequestEngine.cs index 185f86c37..66be18cf6 100644 --- a/src/Ombi.Core/Engine/MusicRequestEngine.cs +++ b/src/Ombi.Core/Engine/MusicRequestEngine.cs @@ -299,7 +299,7 @@ namespace Ombi.Core.Engine return await ApproveAlbum(request); } - public async Task DenyAlbumById(int modelId) + public async Task DenyAlbumById(int modelId, string reason) { var request = await MusicRepository.Find(modelId); if (request == null) @@ -311,6 +311,7 @@ namespace Ombi.Core.Engine } request.Denied = true; + request.DeniedReason = reason; // We are denying a request NotificationHelper.Notify(request, NotificationType.RequestDeclined); await MusicRepository.Update(request); diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index 290bedd6b..ddcc22d7b 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -403,7 +403,7 @@ namespace Ombi.Core.Engine }; } - public async Task DenyChildRequest(int requestId) + public async Task DenyChildRequest(int requestId, string reason) { var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId); if (request == null) @@ -414,6 +414,7 @@ namespace Ombi.Core.Engine }; } request.Denied = true; + request.DeniedReason = reason; await TvRepository.UpdateChild(request); NotificationHelper.Notify(request, NotificationType.RequestDeclined); return new RequestEngineResult diff --git a/src/Ombi.Core/Models/Requests/MovieRequestViewModel.cs b/src/Ombi.Core/Models/Requests/MovieRequestViewModel.cs index c67e138e1..92e221abd 100644 --- a/src/Ombi.Core/Models/Requests/MovieRequestViewModel.cs +++ b/src/Ombi.Core/Models/Requests/MovieRequestViewModel.cs @@ -29,5 +29,6 @@ namespace Ombi.Core.Models.Requests public class MovieRequestViewModel { public int TheMovieDbId { get; set; } + public string LanguageCode { get; set; } = "en"; } } \ No newline at end of file diff --git a/src/Ombi.Core/Ombi.Core.csproj b/src/Ombi.Core/Ombi.Core.csproj index fb1024b93..35688a6fe 100644 --- a/src/Ombi.Core/Ombi.Core.csproj +++ b/src/Ombi.Core/Ombi.Core.csproj @@ -11,11 +11,11 @@ - - - + + + - + diff --git a/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs b/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs new file mode 100644 index 000000000..428de9ce5 --- /dev/null +++ b/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs @@ -0,0 +1,97 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Ombi.Core.Models.Search; +using Ombi.Store.Entities; +using Ombi.Store.Repository.Requests; + +namespace Ombi.Core.Rule.Rules.Search +{ + public static class AvailabilityRuleHelper + { + public static void CheckForUnairedEpisodes(SearchTvShowViewModel search) + { + if (search.SeasonRequests.All(x => x.Episodes.All(e => e.Available))) + { + search.FullyAvailable = true; + } + else + { + var airedButNotAvailable = search.SeasonRequests.Any(x => + x.Episodes.Any(c => !c.Available && c.AirDate <= DateTime.Now.Date && c.AirDate != DateTime.MinValue)); + if (!airedButNotAvailable) + { + var unairedEpisodes = search.SeasonRequests.Any(x => + x.Episodes.Any(c => !c.Available && c.AirDate > DateTime.Now.Date)); + if (unairedEpisodes) + { + search.FullyAvailable = true; + } + } + } + } + + public static async Task SingleEpisodeCheck(bool useImdb, IQueryable allEpisodes, EpisodeRequests episode, + SeasonRequests season, PlexServerContent item, bool useTheMovieDb, bool useTvDb) + { + PlexEpisode epExists = null; + if (useImdb) + { + epExists = await allEpisodes.FirstOrDefaultAsync(x => + x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && + x.Series.ImdbId == item.ImdbId.ToString()); + } + + if (useTheMovieDb) + { + epExists = await allEpisodes.FirstOrDefaultAsync(x => + x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && + x.Series.TheMovieDbId == item.TheMovieDbId.ToString()); + } + + if (useTvDb) + { + epExists = await allEpisodes.FirstOrDefaultAsync(x => + x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && + x.Series.TvDbId == item.TvDbId.ToString()); + } + + if (epExists != null) + { + episode.Available = true; + } + } + public static async Task SingleEpisodeCheck(bool useImdb, IQueryable allEpisodes, EpisodeRequests episode, + SeasonRequests season, EmbyContent item, bool useTheMovieDb, bool useTvDb) + { + EmbyEpisode epExists = null; + if (useImdb) + { + epExists = await allEpisodes.FirstOrDefaultAsync(x => + x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && + x.Series.ImdbId == item.ImdbId.ToString()); + } + + if (useTheMovieDb) + { + epExists = await allEpisodes.FirstOrDefaultAsync(x => + x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && + x.Series.TheMovieDbId == item.TheMovieDbId.ToString()); + } + + if (useTvDb) + { + epExists = await allEpisodes.FirstOrDefaultAsync(x => + x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && + x.Series.TvDbId == item.TvDbId.ToString()); + } + + if (epExists != null) + { + episode.Available = true; + } + } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs index 486de9ea8..3171c6ada 100644 --- a/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs @@ -1,6 +1,4 @@ -using System; -using System.Linq; -using System.Linq.Expressions; +using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Ombi.Core.Models.Search; @@ -23,15 +21,27 @@ namespace Ombi.Core.Rule.Rules.Search public async Task Execute(SearchViewModel obj) { EmbyContent item = null; + var useImdb = false; + var useTheMovieDb = false; + var useTvDb = false; + if (obj.ImdbId.HasValue()) { item = await EmbyContentRepository.GetByImdbId(obj.ImdbId); + if (item != null) + { + useImdb = true; + } } if (item == null) { if (obj.TheMovieDbId.HasValue()) { item = await EmbyContentRepository.GetByTheMovieDbId(obj.TheMovieDbId); + if (item != null) + { + useTheMovieDb = true; + } } if (item == null) @@ -39,10 +49,14 @@ namespace Ombi.Core.Rule.Rules.Search if (obj.TheTvDbId.HasValue()) { item = await EmbyContentRepository.GetByTvDbId(obj.TheTvDbId); + if (item != null) + { + useTvDb = true; + } } } } - + if (item != null) { obj.Available = true; @@ -59,29 +73,12 @@ namespace Ombi.Core.Rule.Rules.Search { foreach (var episode in season.Episodes) { - EmbyEpisode epExists = null; - - if (item.HasImdb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(e => e.EpisodeNumber == episode.EpisodeNumber && e.SeasonNumber == season.SeasonNumber - && e.ImdbId == item.ImdbId); - } if (item.HasTvDb && epExists == null) - { - epExists = await allEpisodes.FirstOrDefaultAsync(e => e.EpisodeNumber == episode.EpisodeNumber && e.SeasonNumber == season.SeasonNumber - && e.Series.TvDbId == item.TvDbId); - } if (item.HasTheMovieDb && epExists == null) - { - epExists = await allEpisodes.FirstOrDefaultAsync(e => e.EpisodeNumber == episode.EpisodeNumber && e.SeasonNumber == season.SeasonNumber - && e.TheMovieDbId == item.TheMovieDbId); - } - - if (epExists != null) - { - episode.Available = true; - } + await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb); } } } + + AvailabilityRuleHelper.CheckForUnairedEpisodes(search); } } return Success(); diff --git a/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs index e1ddcecd0..7f79e4165 100644 --- a/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs @@ -1,7 +1,5 @@ -using System; -using System.Linq; +using System.Linq; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; using Ombi.Core.Models.Search; using Ombi.Core.Rule.Interfaces; using Ombi.Helpers; @@ -74,56 +72,17 @@ namespace Ombi.Core.Rule.Rules.Search { foreach (var episode in season.Episodes) { - PlexEpisode epExists = null; - if (useImdb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && - x.Series.ImdbId == item.ImdbId.ToString()); - } - if (useTheMovieDb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && - x.Series.TheMovieDbId == item.TheMovieDbId.ToString()); - } - if (useTvDb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && - x.Series.TvDbId == item.TvDbId.ToString()); - } - - if (epExists != null) - { - episode.Available = true; - } + await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb); } } - if (search.SeasonRequests.All(x => x.Episodes.All(e => e.Available))) - { - search.FullyAvailable = true; - } - else - { - var airedButNotAvailable = search.SeasonRequests.Any(x => - x.Episodes.Any(c => !c.Available && c.AirDate <= DateTime.Now.Date)); - if (!airedButNotAvailable) - { - var unairedEpisodes = search.SeasonRequests.Any(x => - x.Episodes.Any(c => !c.Available && c.AirDate > DateTime.Now.Date)); - if (unairedEpisodes) - { - search.FullyAvailable = true; - } - } - - } + AvailabilityRuleHelper.CheckForUnairedEpisodes(search); } } } return Success(); } + + } } \ No newline at end of file diff --git a/src/Ombi.Core/Senders/TvSender.cs b/src/Ombi.Core/Senders/TvSender.cs index d0946b6f4..f0784a4ca 100644 --- a/src/Ombi.Core/Senders/TvSender.cs +++ b/src/Ombi.Core/Senders/TvSender.cs @@ -348,16 +348,16 @@ namespace Ombi.Core.Senders if (!existingSeason.monitored) { // We need to monitor it, problem being is all episodes will now be monitored - // So we need to monior the series but unmonitor every episode - // Except the episodes that are already monitored before we update the series (we do not want to unmonitor episodes that are monitored beforehand) + // So we need to monitor the series but unmonitor every episode + // Except the episodes that are already monitored before we update the series (we do not want to unmonitored episodes that are monitored beforehand) existingSeason.monitored = true; var sea = result.seasons.FirstOrDefault(x => x.seasonNumber == existingSeason.seasonNumber); sea.monitored = true; //var previouslyMonitoredEpisodes = sonarrEpList.Where(x => // x.seasonNumber == existingSeason.seasonNumber && x.monitored).Select(x => x.episodeNumber).ToList(); // We probably don't actually care about this result = await SonarrApi.UpdateSeries(result, s.ApiKey, s.FullUri); - var epToUnmonitor = new List(); - var newEpList = sonarrEpList.ConvertAll(ep => new Episode(ep)); // Clone it so we don't modify the orignal member + var epToUnmonitored = new List(); + var newEpList = sonarrEpList.ConvertAll(ep => new Episode(ep)); // Clone it so we don't modify the original member foreach (var ep in newEpList.Where(x => x.seasonNumber == existingSeason.seasonNumber).ToList()) { //if (previouslyMonitoredEpisodes.Contains(ep.episodeNumber)) @@ -366,10 +366,10 @@ namespace Ombi.Core.Senders // continue; //} ep.monitored = false; - epToUnmonitor.Add(ep); + epToUnmonitored.Add(ep); } - foreach (var epToUpdate in epToUnmonitor) + foreach (var epToUpdate in epToUnmonitored) { await SonarrApi.UpdateEpisode(epToUpdate, s.ApiKey, s.FullUri); } diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 190e79203..09dbf4e79 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -200,6 +200,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } } } diff --git a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj index 028c37b43..ec905e718 100644 --- a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj +++ b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj @@ -9,9 +9,9 @@ - - - + + + diff --git a/src/Ombi.Helpers.Tests/Ombi.Helpers.Tests.csproj b/src/Ombi.Helpers.Tests/Ombi.Helpers.Tests.csproj new file mode 100644 index 000000000..0517af22d --- /dev/null +++ b/src/Ombi.Helpers.Tests/Ombi.Helpers.Tests.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp2.2 + + false + + + + + + + + + + + + + diff --git a/src/Ombi.Helpers.Tests/PlexHelperTests.cs b/src/Ombi.Helpers.Tests/PlexHelperTests.cs new file mode 100644 index 000000000..8ecb3fa0a --- /dev/null +++ b/src/Ombi.Helpers.Tests/PlexHelperTests.cs @@ -0,0 +1,52 @@ +using System; +using NUnit.Framework; +using System.Collections.Generic; + +namespace Ombi.Helpers.Tests +{ + [TestFixture] + public class PlexHelperTests + { + + [TestCaseSource(nameof(ProviderIdGuidData))] + public string GetProviderIdFromPlexGuidTests(string guidInput, ProviderIdType type) + { + var result = PlexHelper.GetProviderIdFromPlexGuid(guidInput); + + switch (type) + { + case ProviderIdType.Imdb: + Assert.That(result.ImdbId, Is.Not.Null); + return result.ImdbId; + case ProviderIdType.TvDb: + Assert.That(result.TheTvDb, Is.Not.Null); + return result.TheTvDb; + case ProviderIdType.MovieDb: + Assert.That(result.TheMovieDb, Is.Not.Null); + return result.TheMovieDb; + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } + } + + public static IEnumerable ProviderIdGuidData + { + get + { + yield return new TestCaseData("com.plexapp.agents.thetvdb://269586/2/8?lang=en", ProviderIdType.TvDb).Returns("269586").SetName("Regular TvDb Id"); + yield return new TestCaseData("com.plexapp.agents.themoviedb://390043?lang=en", ProviderIdType.MovieDb).Returns("390043").SetName("Regular MovieDb Id"); + yield return new TestCaseData("com.plexapp.agents.imdb://tt2543164?lang=en", ProviderIdType.Imdb).Returns("tt2543164").SetName("Regular Imdb Id"); + yield return new TestCaseData("com.plexapp.agents.agent47://tt2543456?lang=en", ProviderIdType.Imdb).Returns("tt2543456").SetName("Unknown IMDB agent"); + yield return new TestCaseData("com.plexapp.agents.agent47://456822/1/1?lang=en", ProviderIdType.TvDb).Returns("456822").SetName("Unknown TvDb agent"); + yield return new TestCaseData("com.plexapp.agents.agent47://456822/999/999?lang=en", ProviderIdType.TvDb).Returns("456822").SetName("Unknown TvDb agent, large episode and season"); + } + } + + public enum ProviderIdType + { + Imdb, + TvDb, + MovieDb + } + } +} \ No newline at end of file diff --git a/src/Ombi.Helpers/LoggingEvents.cs b/src/Ombi.Helpers/LoggingEvents.cs index 40ec3fd2b..3893dc879 100644 --- a/src/Ombi.Helpers/LoggingEvents.cs +++ b/src/Ombi.Helpers/LoggingEvents.cs @@ -21,6 +21,7 @@ namespace Ombi.Helpers public static EventId PlexContentCacher => new EventId(2008); public static EventId SickRageCacher => new EventId(2009); public static EventId LidarrArtistCache => new EventId(2010); + public static EventId MediaReferesh => new EventId(2011); public static EventId MovieSender => new EventId(3000); diff --git a/src/Ombi.Helpers/Ombi.Helpers.csproj b/src/Ombi.Helpers/Ombi.Helpers.csproj index 2aaaa076f..5dedaff61 100644 --- a/src/Ombi.Helpers/Ombi.Helpers.csproj +++ b/src/Ombi.Helpers/Ombi.Helpers.csproj @@ -10,9 +10,9 @@ - - - + + + diff --git a/src/Ombi.Helpers/PlexHelper.cs b/src/Ombi.Helpers/PlexHelper.cs index 93710022f..de61b8740 100644 --- a/src/Ombi.Helpers/PlexHelper.cs +++ b/src/Ombi.Helpers/PlexHelper.cs @@ -27,12 +27,15 @@ using System; using System.Globalization; +using System.Text.RegularExpressions; namespace Ombi.Helpers { public class PlexHelper { - + private const string ImdbMatchExpression = "tt([0-9]{1,10})"; + private const string TvDbIdMatchExpression = "//[0-9]+/([0-9]{1,3})/([0-9]{1,3})"; + public static ProviderId GetProviderIdFromPlexGuid(string guid) { //com.plexapp.agents.thetvdb://269586/2/8?lang=en @@ -52,7 +55,7 @@ namespace Ombi.Helpers { TheTvDb = guidSplit[1] }; - } + } else if (guid.Contains("themoviedb", CompareOptions.IgnoreCase)) { return new ProviderId @@ -60,6 +63,7 @@ namespace Ombi.Helpers TheMovieDb = guidSplit[1] }; } + else if (guid.Contains("imdb", CompareOptions.IgnoreCase)) { return new ProviderId @@ -67,6 +71,31 @@ namespace Ombi.Helpers ImdbId = guidSplit[1] }; } + else + { + var imdbRegex = new Regex(ImdbMatchExpression, RegexOptions.Compiled); + var tvdbRegex = new Regex(TvDbIdMatchExpression, RegexOptions.Compiled); + var imdbMatch = imdbRegex.IsMatch(guid); + if (imdbMatch) + { + return new ProviderId + { + ImdbId = guidSplit[1] + }; + } + else + { + // Check if it matches the TvDb pattern + var tvdbMatch = tvdbRegex.IsMatch(guid); + if (tvdbMatch) + { + return new ProviderId + { + TheTvDb = guidSplit[1] + }; + } + } + } } return new ProviderId(); } diff --git a/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html b/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html index 450e7df2a..5456743c9 100644 --- a/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html +++ b/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html @@ -1,10 +1,17 @@ - + + - - + + Ombi - - - - - - - - Ombi Recently Added - - - - - - - - - - - - - - - - {@INTRO} - - - - - - - - - - {@RECENTLYADDED} - - - - - - - -
{@INTRO}