diff --git a/CHANGELOG.md b/CHANGELOG.md index a9fdea5a0..5e60b7be3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,43 @@ ## (unreleased) +### **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] + +### **Fixes** + +- 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] diff --git a/src/Ombi.Api.Emby/EmbyApi.cs b/src/Ombi.Api.Emby/EmbyApi.cs index fa8414ac9..43a2badb6 100644 --- a/src/Ombi.Api.Emby/EmbyApi.cs +++ b/src/Ombi.Api.Emby/EmbyApi.cs @@ -53,8 +53,6 @@ namespace Ombi.Api.Emby { username, pw = password, - password = password.GetSha1Hash().ToLower(), - passwordMd5 = password.CalcuateMd5Hash() }; request.AddJsonBody(body); diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index f1a5b9880..290bedd6b 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -116,6 +116,7 @@ namespace Ombi.Core.Engine } // Remove the ID since this is a new child + // This was a TVDBID for the request rules to run tvBuilder.ChildRequest.Id = 0; if (!tvBuilder.ChildRequest.SeasonRequests.Any()) { diff --git a/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs b/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs index e5277e236..334284484 100644 --- a/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs +++ b/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs @@ -41,7 +41,7 @@ namespace Ombi.Core.Helpers ShowInfo = await TvApi.ShowLookupByTheTvDbId(id); Results = await MovieDbApi.SearchTv(ShowInfo.name); foreach (TvSearchResult result in Results) { - if (result.Name == ShowInfo.name) + if (result.Name.Equals(ShowInfo.name, StringComparison.InvariantCultureIgnoreCase)) { var showIds = await MovieDbApi.GetTvExternals(result.Id); ShowInfo.externals.imdb = showIds.imdb_id; @@ -64,14 +64,15 @@ namespace Ombi.Core.Helpers { ChildRequest = new ChildRequests { - Id = model.TvDbId, + Id = model.TvDbId, // This is set to 0 after the request rules have run, the request rules needs it to identify the request RequestType = RequestType.TvShow, RequestedDate = DateTime.UtcNow, Approved = false, RequestedUserId = userId, SeasonRequests = new List(), Title = ShowInfo.name, - SeriesType = ShowInfo.genres.Any( s => s.Equals("Anime", StringComparison.OrdinalIgnoreCase)) ? SeriesType.Anime : SeriesType.Standard + ReleaseYear = FirstAir, + SeriesType = ShowInfo.genres.Any( s => s.Equals("Anime", StringComparison.InvariantCultureIgnoreCase)) ? SeriesType.Anime : SeriesType.Standard }; return this; diff --git a/src/Ombi.Core/Rule/Rules/Request/ExistingPlexRequestRule.cs b/src/Ombi.Core/Rule/Rules/Request/ExistingPlexRequestRule.cs new file mode 100644 index 000000000..5d7658c83 --- /dev/null +++ b/src/Ombi.Core/Rule/Rules/Request/ExistingPlexRequestRule.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Ombi.Core.Rule.Interfaces; +using Ombi.Store.Entities; +using Ombi.Store.Entities.Requests; +using Ombi.Store.Repository; + +namespace Ombi.Core.Rule.Rules.Request +{ + public class ExistingPlexRequestRule : BaseRequestRule, IRules + { + public ExistingPlexRequestRule(IPlexContentRepository rv) + { + _plexContent = rv; + } + + private readonly IPlexContentRepository _plexContent; + + /// + /// We check if the request exists, if it does then we don't want to re-request it. + /// + /// The object. + /// + public async Task Execute(BaseRequest obj) + { + if (obj.RequestType == RequestType.TvShow) + { + var tvRequest = (ChildRequests) obj; + + var tvContent = _plexContent.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Show); + // We need to do a check on the TVDBId + var anyTvDbMatches = await tvContent.Include(x => x.Episodes).FirstOrDefaultAsync(x => x.HasTvDb && x.TvDbId.Equals(tvRequest.Id.ToString())); // the Id on the child is the tvdbid at this point + if (anyTvDbMatches == null) + { + // So we do not have a TVDB Id, that really sucks. + // Let's try and match on the title and year of the show + var titleAndYearMatch = await tvContent.Include(x=> x.Episodes).FirstOrDefaultAsync(x => + x.Title.Equals(tvRequest.Title, StringComparison.InvariantCultureIgnoreCase) + && x.ReleaseYear == tvRequest.ReleaseYear.Year.ToString()); + if (titleAndYearMatch != null) + { + // We have a match! Suprise Motherfucker + return CheckExistingContent(tvRequest, titleAndYearMatch); + } + + // We do not have this + return Success(); + } + // looks like we have a match on the TVDbID + return CheckExistingContent(tvRequest, anyTvDbMatches); + } + return Success(); + } + + + private RuleResult CheckExistingContent(ChildRequests child, PlexServerContent content) + { + foreach (var season in child.SeasonRequests) + { + var currentSeasonRequest = + content.Episodes.Where(x => x.SeasonNumber == season.SeasonNumber).ToList(); + if (!currentSeasonRequest.Any()) + { + continue; + } + foreach (var e in season.Episodes) + { + var hasEpisode = currentSeasonRequest.Any(x => x.EpisodeNumber == e.EpisodeNumber); + if (hasEpisode) + { + return Fail($"We already have episodes requested from series {child.Title}"); + } + } + } + + return Success(); + } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Senders/MovieSender.cs b/src/Ombi.Core/Senders/MovieSender.cs index 8b89ef7bb..66978f758 100644 --- a/src/Ombi.Core/Senders/MovieSender.cs +++ b/src/Ombi.Core/Senders/MovieSender.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -101,13 +102,17 @@ namespace Ombi.Core.Senders var profiles = await _userProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == model.RequestedUserId); if (profiles != null) { - if (profiles.SonarrRootPathAnime > 0) - { - rootFolderPath = await RadarrRootPath(profiles.SonarrRootPathAnime, settings); + if (profiles.RadarrRootPath > 0) + { + var tempPath = await RadarrRootPath(profiles.RadarrRootPath, settings); + if (tempPath.HasValue()) + { + rootFolderPath = tempPath; + } } - if (profiles.SonarrQualityProfileAnime > 0) + if (profiles.RadarrQualityProfile > 0) { - qualityToUse = profiles.SonarrQualityProfileAnime; + qualityToUse = profiles.RadarrQualityProfile; } } @@ -163,7 +168,7 @@ namespace Ombi.Core.Senders { var paths = await RadarrApi.GetRootFolders(settings.ApiKey, settings.FullUri); var selectedPath = paths.FirstOrDefault(x => x.id == overrideId); - return selectedPath.path; + return selectedPath?.path ?? String.Empty; } } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/Requests/ChildRequests.cs b/src/Ombi.Store/Entities/Requests/ChildRequests.cs index 3b5156ce5..f212aa3e7 100644 --- a/src/Ombi.Store/Entities/Requests/ChildRequests.cs +++ b/src/Ombi.Store/Entities/Requests/ChildRequests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using Ombi.Store.Repository.Requests; @@ -22,6 +23,8 @@ namespace Ombi.Store.Entities.Requests [NotMapped] public bool ShowSubscribe { get; set; } + [NotMapped] + public DateTime ReleaseYear { get; set; } // Used in the ExistingPlexRequestRule.cs [ForeignKey(nameof(IssueId))] public List Issues { get; set; } diff --git a/src/Ombi/ClientApp/app/landingpage/landingpage.component.html b/src/Ombi/ClientApp/app/landingpage/landingpage.component.html index 27545b64b..03878033f 100644 --- a/src/Ombi/ClientApp/app/landingpage/landingpage.component.html +++ b/src/Ombi/ClientApp/app/landingpage/landingpage.component.html @@ -3,7 +3,7 @@
-
+
diff --git a/src/Ombi/ClientApp/app/requests/request.component.html b/src/Ombi/ClientApp/app/requests/request.component.html index d2df3c97a..db72b9d17 100644 --- a/src/Ombi/ClientApp/app/requests/request.component.html +++ b/src/Ombi/ClientApp/app/requests/request.component.html @@ -9,7 +9,7 @@ {{ 'Requests.TvTab' | translate }} -
  • +
  • {{ 'Requests.MusicTab' | translate }}
  • diff --git a/src/Ombi/ClientApp/app/requests/request.component.ts b/src/Ombi/ClientApp/app/requests/request.component.ts index d0fa9d0b1..b318d619b 100644 --- a/src/Ombi/ClientApp/app/requests/request.component.ts +++ b/src/Ombi/ClientApp/app/requests/request.component.ts @@ -15,6 +15,7 @@ export class RequestComponent implements OnInit { public issueCategories: IIssueCategory[]; public issuesEnabled = false; + public musicEnabled: boolean; constructor(private issuesService: IssuesService, private settingsService: SettingsService) { @@ -23,6 +24,7 @@ export class RequestComponent implements OnInit { public ngOnInit(): void { this.issuesService.getCategories().subscribe(x => this.issueCategories = x); + this.settingsService.lidarrEnabled().subscribe(x => this.musicEnabled = x); this.settingsService.getIssueSettings().subscribe(x => this.issuesEnabled = x.enabled); } diff --git a/src/Ombi/ClientApp/app/search/moviesearch.component.html b/src/Ombi/ClientApp/app/search/moviesearch.component.html index b51dec5a6..a31bed3b5 100644 --- a/src/Ombi/ClientApp/app/search/moviesearch.component.html +++ b/src/Ombi/ClientApp/app/search/moviesearch.component.html @@ -2,7 +2,8 @@
    - +

    {{result.title}} ({{result.releaseDate | amLocal | amDateFormat: 'YYYY'}})

    - - {{ 'Search.TheatricalRelease' | translate: {date: result.releaseDate | amLocal | amDateFormat: 'LL'} }} - {{ 'Search.DigitalDate' | translate: {date: result.digitalReleaseDate | amLocal | amDateFormat: 'LL'} }} + + {{ + 'Search.TheatricalRelease' | translate: {date: result.releaseDate | amLocal | + amDateFormat: 'LL'} }} + {{ 'Search.DigitalDate' | translate: {date: result.digitalReleaseDate | + amLocal | amDateFormat: 'LL'} }} - + - - {{result.quality}}p - - - - - + + {{result.quality}}p + + + + + - + -
    +

    {{result.overview}}

    -
    -
    - - - -
    -
    - +
    -
    - - - - - - -
    - - -
    +
    + + + + + + +
    + + + +
    -
    -
    +
    +
    @@ -117,4 +136,4 @@ + [issueCategory]="issueCategorySelected" [id]="issueRequestId" [providerId]="issueProviderId"> \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/search/moviesearch.component.ts b/src/Ombi/ClientApp/app/search/moviesearch.component.ts index f4d19565a..600fc19eb 100644 --- a/src/Ombi/ClientApp/app/search/moviesearch.component.ts +++ b/src/Ombi/ClientApp/app/search/moviesearch.component.ts @@ -172,7 +172,7 @@ export class MovieSearchComponent implements OnInit { r.subscribed = true; this.requestService.subscribeToMovie(r.requestId) .subscribe(x => { - this.notificationService.success("Subscribed To Movie!"); + this.notificationService.success(`Subscribed To Movie ${r.title}!`); }); } diff --git a/src/Ombi/Controllers/IdentityController.cs b/src/Ombi/Controllers/IdentityController.cs index 61b3f06d8..f963db0b8 100644 --- a/src/Ombi/Controllers/IdentityController.cs +++ b/src/Ombi/Controllers/IdentityController.cs @@ -863,6 +863,7 @@ namespace Ombi.Controllers { var ombiUser = new OmbiUser { + Alias = user.Alias, Email = user.EmailAddress, UserName = user.UserName };