mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-08 06:00:50 -07:00
We now show streaming information on the details page
This commit is contained in:
parent
88453f0a99
commit
ea7307ac07
38 changed files with 3267 additions and 154 deletions
94
src/Ombi.Core.Tests/WatchProviderParserTests.cs
Normal file
94
src/Ombi.Core.Tests/WatchProviderParserTests.cs
Normal file
|
@ -0,0 +1,94 @@
|
|||
using NUnit.Framework;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Core.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Core.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class WatchProviderParserTests
|
||||
{
|
||||
[TestCase("GB", TestName = "UpperCase")]
|
||||
[TestCase("gb", TestName = "LowerCase")]
|
||||
[TestCase("gB", TestName = "MixedCase")]
|
||||
public void GetValidStreamData(string streamingCountry)
|
||||
{
|
||||
var result = WatchProviderParser.GetUserWatchProviders(new WatchProviders
|
||||
{
|
||||
Results = new Results
|
||||
{
|
||||
GB = new WatchProviderData()
|
||||
{
|
||||
StreamInformation = new List<StreamData>
|
||||
{
|
||||
new StreamData
|
||||
{
|
||||
provider_name = "Netflix",
|
||||
display_priority = 0,
|
||||
logo_path = "logo",
|
||||
provider_id = 8
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, new OmbiUser { StreamingCountry = streamingCountry });
|
||||
|
||||
Assert.That(result[0].provider_name, Is.EqualTo("Netflix"));
|
||||
}
|
||||
|
||||
[TestCase("GB", TestName = "Missing_UpperCase")]
|
||||
[TestCase("gb", TestName = "Missing_LowerCase")]
|
||||
[TestCase("gB", TestName = "Missing_MixedCase")]
|
||||
public void GetMissingStreamData(string streamingCountry)
|
||||
{
|
||||
var result = WatchProviderParser.GetUserWatchProviders(new WatchProviders
|
||||
{
|
||||
Results = new Results
|
||||
{
|
||||
AR = new WatchProviderData()
|
||||
{
|
||||
StreamInformation = new List<StreamData>
|
||||
{
|
||||
new StreamData
|
||||
{
|
||||
provider_name = "Netflix",
|
||||
display_priority = 0,
|
||||
logo_path = "logo",
|
||||
provider_id = 8
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, new OmbiUser { StreamingCountry = streamingCountry });
|
||||
|
||||
Assert.That(result, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetInvalidStreamData()
|
||||
{
|
||||
var result = WatchProviderParser.GetUserWatchProviders(new WatchProviders
|
||||
{
|
||||
Results = new Results
|
||||
{
|
||||
AR = new WatchProviderData()
|
||||
{
|
||||
StreamInformation = new List<StreamData>
|
||||
{
|
||||
new StreamData
|
||||
{
|
||||
provider_name = "Netflix",
|
||||
display_priority = 0,
|
||||
logo_path = "logo",
|
||||
provider_id = 8
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, new OmbiUser { StreamingCountry = "BLAH" });
|
||||
|
||||
Assert.That(result, Is.Empty);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@ using Ombi.Core.Settings;
|
|||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Core.Helpers;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
|
@ -179,6 +181,12 @@ namespace Ombi.Core.Engine
|
|||
return user.Language;
|
||||
}
|
||||
|
||||
protected async Task<List<StreamData>> GetUserWatchProvider(WatchProviders providers)
|
||||
{
|
||||
var user = await GetUser();
|
||||
return WatchProviderParser.GetUserWatchProviders(providers, user);
|
||||
}
|
||||
|
||||
private OmbiSettings ombiSettings;
|
||||
protected async Task<OmbiSettings> GetOmbiSettings()
|
||||
{
|
||||
|
|
|
@ -26,5 +26,6 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
int ResultLimit { get; set; }
|
||||
|
||||
Task<MovieFullInfoViewModel> GetMovieInfoByImdbId(string imdbId, CancellationToken requestAborted);
|
||||
Task<IEnumerable<StreamingData>> GetStreamInformation(int movieDbId, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
|
||||
namespace Ombi.Core
|
||||
|
@ -7,5 +9,6 @@ namespace Ombi.Core
|
|||
{
|
||||
Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid);
|
||||
Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId);
|
||||
Task<IEnumerable<StreamingData>> GetStreamInformation(int tvDbId, int tvMazeId, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
|
@ -249,6 +249,26 @@ namespace Ombi.Core.Engine.V2
|
|||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<StreamingData>> GetStreamInformation(int movieDbId, CancellationToken cancellationToken)
|
||||
{
|
||||
var providers = await MovieApi.GetMovieWatchProviders(movieDbId, cancellationToken);
|
||||
var results = await GetUserWatchProvider(providers);
|
||||
|
||||
var data = new List<StreamingData>();
|
||||
|
||||
foreach (var result in results)
|
||||
{
|
||||
data.Add(new StreamingData
|
||||
{
|
||||
Logo = result.logo_path,
|
||||
Order = result.display_priority,
|
||||
StreamingProvider = result.provider_name
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
protected async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(
|
||||
IEnumerable<MovieSearchResult> movies)
|
||||
{
|
||||
|
|
|
@ -19,6 +19,8 @@ using Ombi.Core.Settings;
|
|||
using Ombi.Store.Repository;
|
||||
using TraktSharp.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Threading;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
|
||||
namespace Ombi.Core.Engine.V2
|
||||
{
|
||||
|
@ -27,15 +29,17 @@ namespace Ombi.Core.Engine.V2
|
|||
private readonly ITvMazeApi _tvMaze;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly ITraktApi _traktApi;
|
||||
private readonly IMovieDbApi _movieApi;
|
||||
|
||||
public TvSearchEngineV2(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
|
||||
ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache, ISettingsService<OmbiSettings> s,
|
||||
IRepository<RequestSubscription> sub)
|
||||
IRepository<RequestSubscription> sub, IMovieDbApi movieApi)
|
||||
: base(identity, service, r, um, memCache, s, sub)
|
||||
{
|
||||
_tvMaze = tvMaze;
|
||||
_mapper = mapper;
|
||||
_traktApi = trakt;
|
||||
_movieApi = movieApi;
|
||||
}
|
||||
|
||||
|
||||
|
@ -106,6 +110,39 @@ namespace Ombi.Core.Engine.V2
|
|||
return await ProcessResult(mapped, traktInfoTask);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<StreamingData>> GetStreamInformation(int tvDbId, int tvMazeId, CancellationToken cancellationToken)
|
||||
{
|
||||
var tvdbshow = await Cache.GetOrAdd(nameof(GetShowInformation) + tvMazeId,
|
||||
async () => await _tvMaze.ShowLookupByTheTvDbId(tvMazeId), DateTime.Now.AddHours(12));
|
||||
if (tvdbshow == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// this is a best effort guess since TV maze do not provide the TheMovieDbId
|
||||
var movieDbResults = await _movieApi.SearchTv(tvdbshow.name, tvdbshow.premiered.Substring(0, 4));
|
||||
var potential = movieDbResults.FirstOrDefault();
|
||||
tvDbId = potential.Id;
|
||||
// end guess
|
||||
|
||||
var providers = await _movieApi.GetTvWatchProviders(tvDbId, cancellationToken);
|
||||
var results = await GetUserWatchProvider(providers);
|
||||
|
||||
var data = new List<StreamingData>();
|
||||
|
||||
foreach (var result in results)
|
||||
{
|
||||
data.Add(new StreamingData
|
||||
{
|
||||
Logo = result.logo_path,
|
||||
Order = result.display_priority,
|
||||
StreamingProvider = result.provider_name
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private IEnumerable<SearchTvShowViewModel> ProcessResults<T>(IEnumerable<T> items)
|
||||
{
|
||||
var retVal = new List<SearchTvShowViewModel>();
|
||||
|
|
35
src/Ombi.Core/Helpers/WatchProviderParser.cs
Normal file
35
src/Ombi.Core/Helpers/WatchProviderParser.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ombi.Core.Helpers
|
||||
{
|
||||
public static class WatchProviderParser
|
||||
{
|
||||
public static List<StreamData> GetUserWatchProviders(WatchProviders providers, OmbiUser user)
|
||||
{
|
||||
var data = new List<StreamData>();
|
||||
|
||||
if (providers?.Results == null)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
var resultsProp = providers.Results.GetType().GetProperties();
|
||||
var matchingStreamingCountry = resultsProp.FirstOrDefault(x => x.Name.Equals(user.StreamingCountry, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (matchingStreamingCountry == null)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
var result = (WatchProviderData)matchingStreamingCountry.GetValue(providers.Results);
|
||||
if (result == null || result.StreamInformation == null)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
return result.StreamInformation;
|
||||
}
|
||||
}
|
||||
}
|
9
src/Ombi.Core/Models/Search/V2/StreamingData.cs
Normal file
9
src/Ombi.Core/Models/Search/V2/StreamingData.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ombi.Core.Models.Search.V2
|
||||
{
|
||||
public class StreamingData
|
||||
{
|
||||
public int Order { get; set; }
|
||||
public string StreamingProvider { get; set; }
|
||||
public string Logo { get; set; }
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ namespace Ombi.Core.Models.UI
|
|||
public UserType UserType { get; set; }
|
||||
public int MovieRequestLimit { get; set; }
|
||||
public int EpisodeRequestLimit { get; set; }
|
||||
public string StreamingCountry { get; set; }
|
||||
public RequestQuotaCountModel EpisodeRequestQuota { get; set; }
|
||||
public RequestQuotaCountModel MovieRequestQuota { get; set; }
|
||||
public RequestQuotaCountModel MusicRequestQuota { get; set; }
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Newtonsoft.Json;
|
||||
using Ombi.Helpers;
|
||||
|
||||
namespace Ombi.Store.Entities
|
||||
{
|
||||
|
@ -21,6 +21,12 @@ namespace Ombi.Store.Entities
|
|||
|
||||
public string Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to get the Streaming information for media
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string StreamingCountry { get; set; }
|
||||
|
||||
public int? MovieRequestLimit { get; set; }
|
||||
public int? EpisodeRequestLimit { get; set; }
|
||||
public int? MusicRequestLimit { get; set; }
|
||||
|
|
|
@ -14,29 +14,6 @@ If running migrations for any db provider other than Sqlite, then ensure the dat
|
|||
export PATH="$HOME/.dotnet/tools:$PATH"
|
||||
```
|
||||
|
||||
1. In `src/Ombi`, install the `Microsoft.EntityFrameworkCore.Design` package:
|
||||
|
||||
```
|
||||
cd src/Ombi
|
||||
dotnet add package Microsoft.EntityFrameworkCore.Design
|
||||
```
|
||||
|
||||
1. For some reason, the `StartupSingleton.Instance.SecurityKey` in `src/Ombi/Extensions/StartupExtensions.cs` is invalid when running `dotnet ef migrations add` so we must fix it; apply this patch which seems to do the job:
|
||||
|
||||
```
|
||||
@@ -79,7 +79,7 @@ namespace Ombi
|
||||
var tokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
- IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(StartupSingleton.Instance.SecurityKey)),
|
||||
+ IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(StartupSingleton.Instance.SecurityKey + "s")),
|
||||
RequireExpirationTime = true,
|
||||
ValidateLifetime = true,
|
||||
ValidAudience = "Ombi",
|
||||
```
|
||||
|
||||
*WARNING*: Don't forget to undo this before building Ombi, or things will be broken!
|
||||
|
||||
1. List the available `dbcontext`s, and select the one that matches the database your fields will go in:
|
||||
|
||||
```
|
||||
|
|
1225
src/Ombi.Store/Migrations/OmbiMySql/20210106132735_UserStreamingCountry.Designer.cs
generated
Normal file
1225
src/Ombi.Store/Migrations/OmbiMySql/20210106132735_UserStreamingCountry.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,26 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ombi.Store.Migrations.OmbiMySql
|
||||
{
|
||||
public partial class UserStreamingCountry : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "StreamingCountry",
|
||||
table: "AspNetUsers",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
defaultValue: "US");
|
||||
|
||||
migrationBuilder.Sql("UPDATE AspNetUsers SET StreamingCountry = 'US'");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StreamingCountry",
|
||||
table: "AspNetUsers");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,8 +14,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "3.1.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64)
|
||||
.HasAnnotation("ProductVersion", "5.0.1");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
|
@ -27,18 +27,18 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("varchar(256)")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasColumnType("varchar(256)")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
@ -257,8 +257,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasColumnType("varchar(256)")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
@ -285,12 +285,12 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasColumnType("varchar(256)")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasColumnType("varchar(256)")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("longtext");
|
||||
|
@ -307,6 +307,9 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("StreamingCountry")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
|
@ -314,8 +317,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasColumnType("varchar(256)")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<int>("UserType")
|
||||
.HasColumnType("int");
|
||||
|
@ -323,11 +326,11 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
@ -1017,6 +1020,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
|
@ -1024,6 +1029,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("NotificationUserIds")
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
|
||||
|
@ -1031,6 +1038,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.AlbumRequest", b =>
|
||||
|
@ -1038,6 +1047,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
|
||||
b.Navigation("RequestedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
|
@ -1051,6 +1062,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
|
||||
b.Navigation("ParentRequest");
|
||||
|
||||
b.Navigation("RequestedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
|
@ -1062,6 +1077,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("Issues");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
|
@ -1083,6 +1102,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserReportedId");
|
||||
|
||||
b.Navigation("IssueCategory");
|
||||
|
||||
b.Navigation("UserReported");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
|
@ -1090,6 +1113,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
|
||||
b.Navigation("RequestedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
|
@ -1097,6 +1122,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
|
@ -1104,6 +1131,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.UserNotificationPreferences", b =>
|
||||
|
@ -1111,6 +1140,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("UserNotificationPreferences")
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.UserQualityProfiles", b =>
|
||||
|
@ -1118,6 +1149,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Votes", b =>
|
||||
|
@ -1125,6 +1158,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
|
@ -1134,6 +1169,8 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
.HasForeignKey("SeasonId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Season");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
|
@ -1143,6 +1180,42 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
|||
.HasForeignKey("ChildRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ChildRequest");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
|
||||
{
|
||||
b.Navigation("NotificationUserIds");
|
||||
|
||||
b.Navigation("UserNotificationPreferences");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.Navigation("Issues");
|
||||
|
||||
b.Navigation("SeasonRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.Navigation("Comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.Navigation("Issues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
|
||||
{
|
||||
b.Navigation("ChildRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.Navigation("Episodes");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
|
|
1225
src/Ombi.Store/Migrations/OmbiSqlite/20210106134000_UserStreamingCountry.Designer.cs
generated
Normal file
1225
src/Ombi.Store/Migrations/OmbiSqlite/20210106134000_UserStreamingCountry.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,26 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ombi.Store.Migrations.OmbiSqlite
|
||||
{
|
||||
public partial class UserStreamingCountry : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "StreamingCountry",
|
||||
table: "AspNetUsers",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: "US");
|
||||
|
||||
migrationBuilder.Sql("UPDATE AspNetUsers SET StreamingCountry = 'US'");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StreamingCountry",
|
||||
table: "AspNetUsers");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "3.1.1");
|
||||
.HasAnnotation("ProductVersion", "5.0.1");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
|
@ -26,18 +26,18 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
@ -256,8 +256,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
@ -284,12 +284,12 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
@ -306,6 +306,10 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("StreamingCountry")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@ -313,8 +317,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("UserType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
@ -322,11 +326,11 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
@ -1016,6 +1020,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
|
@ -1023,6 +1029,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("NotificationUserIds")
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
|
||||
|
@ -1030,6 +1038,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.AlbumRequest", b =>
|
||||
|
@ -1037,6 +1047,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
|
||||
b.Navigation("RequestedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
|
@ -1050,6 +1062,10 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
|
||||
b.Navigation("ParentRequest");
|
||||
|
||||
b.Navigation("RequestedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
|
@ -1061,6 +1077,10 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("Issues");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
|
@ -1082,6 +1102,10 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserReportedId");
|
||||
|
||||
b.Navigation("IssueCategory");
|
||||
|
||||
b.Navigation("UserReported");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
|
@ -1089,6 +1113,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
|
||||
b.Navigation("RequestedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
|
@ -1096,6 +1122,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
|
@ -1103,6 +1131,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.UserNotificationPreferences", b =>
|
||||
|
@ -1110,6 +1140,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("UserNotificationPreferences")
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.UserQualityProfiles", b =>
|
||||
|
@ -1117,6 +1149,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Votes", b =>
|
||||
|
@ -1124,6 +1158,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
|
@ -1133,6 +1169,8 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
.HasForeignKey("SeasonId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Season");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
|
@ -1142,6 +1180,42 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
.HasForeignKey("ChildRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ChildRequest");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
|
||||
{
|
||||
b.Navigation("NotificationUserIds");
|
||||
|
||||
b.Navigation("UserNotificationPreferences");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.Navigation("Issues");
|
||||
|
||||
b.Navigation("SeasonRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.Navigation("Comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.Navigation("Issues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
|
||||
{
|
||||
b.Navigation("ChildRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.Navigation("Episodes");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Ombi.Api.TheMovieDb
|
|||
Task<List<MovieSearchResult>> NowPlaying(string languageCode, int? page = null);
|
||||
Task<List<MovieSearchResult>> PopularMovies(string languageCode, int? page = null, CancellationToken cancellationToken = default(CancellationToken));
|
||||
Task<List<MovieSearchResult>> SearchMovie(string searchTerm, int? year, string languageCode);
|
||||
Task<List<TvSearchResult>> SearchTv(string searchTerm);
|
||||
Task<List<TvSearchResult>> SearchTv(string searchTerm, string year = default);
|
||||
Task<List<MovieSearchResult>> TopRated(string languageCode, int? page = null);
|
||||
Task<List<MovieSearchResult>> Upcoming(string languageCode, int? page = null);
|
||||
Task<List<MovieSearchResult>> SimilarMovies(int movieId, string langCode);
|
||||
|
@ -28,5 +28,7 @@ namespace Ombi.Api.TheMovieDb
|
|||
Task<Collections> GetCollection(string langCode, int collectionId, CancellationToken cancellationToken);
|
||||
Task<List<Keyword>> SearchKeyword(string searchTerm);
|
||||
Task<Keyword> GetKeyword(int keywordId);
|
||||
Task<WatchProviders> GetMovieWatchProviders(int theMoviedbId, CancellationToken token);
|
||||
Task<WatchProviders> GetTvWatchProviders(int theMoviedbId, CancellationToken token);
|
||||
}
|
||||
}
|
77
src/Ombi.TheMovieDbApi/Models/WatchProviders.cs
Normal file
77
src/Ombi.TheMovieDbApi/Models/WatchProviders.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Api.TheMovieDb.Models
|
||||
{
|
||||
public class WatchProviders
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int Id { get; set; }
|
||||
[JsonProperty("results")]
|
||||
public Results Results { get; set; }
|
||||
}
|
||||
|
||||
public class Results
|
||||
{
|
||||
public WatchProviderData AR { get; set; }
|
||||
public WatchProviderData AT { get; set; }
|
||||
public WatchProviderData AU { get; set; }
|
||||
public WatchProviderData BE { get; set; }
|
||||
public WatchProviderData BR { get; set; }
|
||||
public WatchProviderData CA { get; set; }
|
||||
public WatchProviderData CH { get; set; }
|
||||
public WatchProviderData CL { get; set; }
|
||||
public WatchProviderData CO { get; set; }
|
||||
public WatchProviderData CZ { get; set; }
|
||||
public WatchProviderData DE { get; set; }
|
||||
public WatchProviderData DK { get; set; }
|
||||
public WatchProviderData EC { get; set; }
|
||||
public WatchProviderData EE { get; set; }
|
||||
public WatchProviderData ES { get; set; }
|
||||
public WatchProviderData FI { get; set; }
|
||||
public WatchProviderData FR { get; set; }
|
||||
public WatchProviderData GB { get; set; }
|
||||
public WatchProviderData GR { get; set; }
|
||||
public WatchProviderData HU { get; set; }
|
||||
public WatchProviderData ID { get; set; }
|
||||
public WatchProviderData IE { get; set; }
|
||||
public WatchProviderData IN { get; set; }
|
||||
public WatchProviderData IT { get; set; }
|
||||
public WatchProviderData JP { get; set; }
|
||||
public WatchProviderData KR { get; set; }
|
||||
public WatchProviderData LT { get; set; }
|
||||
public WatchProviderData LV { get; set; }
|
||||
public WatchProviderData MX { get; set; }
|
||||
public WatchProviderData MY { get; set; }
|
||||
public WatchProviderData NL { get; set; }
|
||||
public WatchProviderData NO { get; set; }
|
||||
public WatchProviderData NZ { get; set; }
|
||||
public WatchProviderData PE { get; set; }
|
||||
public WatchProviderData PH { get; set; }
|
||||
public WatchProviderData PL { get; set; }
|
||||
public WatchProviderData PT { get; set; }
|
||||
public WatchProviderData RU { get; set; }
|
||||
public WatchProviderData SE { get; set; }
|
||||
public WatchProviderData SG { get; set; }
|
||||
public WatchProviderData TH { get; set; }
|
||||
public WatchProviderData TR { get; set; }
|
||||
public WatchProviderData US { get; set; }
|
||||
public WatchProviderData VE { get; set; }
|
||||
public WatchProviderData ZA { get; set; }
|
||||
}
|
||||
|
||||
public class WatchProviderData
|
||||
{
|
||||
public string link { get; set; }
|
||||
[JsonProperty("flatrate")]
|
||||
public List<StreamData> StreamInformation { get; set; }
|
||||
}
|
||||
|
||||
public class StreamData
|
||||
{
|
||||
public int display_priority { get; set; }
|
||||
public string logo_path { get; set; }
|
||||
public int provider_id { get; set; }
|
||||
public string provider_name { get; set; }
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ using Nito.AsyncEx;
|
|||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.TheMovieDbApi.Models;
|
||||
|
||||
namespace Ombi.Api.TheMovieDb
|
||||
|
@ -24,7 +25,7 @@ namespace Ombi.Api.TheMovieDb
|
|||
}
|
||||
|
||||
private const string ApiToken = "b8eabaf5608b88d0298aa189dd90bf00";
|
||||
private const string BaseUri ="http://api.themoviedb.org/3/";
|
||||
private const string BaseUri = "http://api.themoviedb.org/3/";
|
||||
private IMapper Mapper { get; }
|
||||
private IApi Api { get; }
|
||||
private AsyncLazy<TheMovieDbSettings> Settings { get; }
|
||||
|
@ -107,11 +108,15 @@ namespace Ombi.Api.TheMovieDb
|
|||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<TvSearchResult>> SearchTv(string searchTerm)
|
||||
public async Task<List<TvSearchResult>> SearchTv(string searchTerm, string year = default)
|
||||
{
|
||||
var request = new Request($"search/tv", BaseUri, HttpMethod.Get);
|
||||
request.AddQueryString("api_key", ApiToken);
|
||||
request.AddQueryString("query", searchTerm);
|
||||
if (year.HasValue())
|
||||
{
|
||||
request.AddQueryString("first_air_date_year", year);
|
||||
}
|
||||
AddRetry(request);
|
||||
|
||||
var result = await Api.Request<TheMovieDbContainer<SearchResult>>(request);
|
||||
|
@ -299,6 +304,32 @@ namespace Ombi.Api.TheMovieDb
|
|||
return keyword == null || keyword.Id == 0 ? null : keyword;
|
||||
}
|
||||
|
||||
public Task<TheMovieDbContainer<MultiSearch>> MultiSearch(string searchTerm, string languageCode, CancellationToken cancellationToken)
|
||||
{
|
||||
var request = new Request("search/multi", BaseUri, HttpMethod.Get);
|
||||
request.AddQueryString("api_key", ApiToken);
|
||||
request.AddQueryString("language", languageCode);
|
||||
request.AddQueryString("query", searchTerm);
|
||||
var result = Api.Request<TheMovieDbContainer<MultiSearch>>(request, cancellationToken);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Task<WatchProviders> GetMovieWatchProviders(int theMoviedbId, CancellationToken token)
|
||||
{
|
||||
var request = new Request($"movie/{theMoviedbId}/watch/providers", BaseUri, HttpMethod.Get);
|
||||
request.AddQueryString("api_key", ApiToken);
|
||||
|
||||
return Api.Request<WatchProviders>(request, token);
|
||||
}
|
||||
|
||||
public Task<WatchProviders> GetTvWatchProviders(int theMoviedbId, CancellationToken token)
|
||||
{
|
||||
var request = new Request($"tv/{theMoviedbId}/watch/providers", BaseUri, HttpMethod.Get);
|
||||
request.AddQueryString("api_key", ApiToken);
|
||||
|
||||
return Api.Request<WatchProviders>(request, token);
|
||||
}
|
||||
|
||||
private async Task AddDiscoverMovieSettings(Request request)
|
||||
{
|
||||
var settings = await Settings;
|
||||
|
@ -309,17 +340,6 @@ namespace Ombi.Api.TheMovieDb
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<TheMovieDbContainer<MultiSearch>> MultiSearch(string searchTerm, string languageCode, CancellationToken cancellationToken)
|
||||
{
|
||||
var request = new Request("search/multi", BaseUri, HttpMethod.Get);
|
||||
request.AddQueryString("api_key", ApiToken);
|
||||
request.AddQueryString("language", languageCode);
|
||||
request.AddQueryString("query", searchTerm);
|
||||
var result = await Api.Request<TheMovieDbContainer<MultiSearch>>(request, cancellationToken);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void AddRetry(Request request)
|
||||
{
|
||||
request.Retry = true;
|
||||
|
|
5
src/Ombi/ClientApp/src/app/interfaces/IStreams.ts
Normal file
5
src/Ombi/ClientApp/src/app/interfaces/IStreams.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export interface IStreamingData {
|
||||
order: number;
|
||||
streamingProvider: string;
|
||||
logo: string;
|
||||
}
|
|
@ -17,6 +17,7 @@ export interface IUser {
|
|||
userAccessToken: string;
|
||||
language: string;
|
||||
userQualityProfiles: IUserQualityProfiles;
|
||||
streamingCountry: string;
|
||||
|
||||
// FOR UI
|
||||
episodeRequestQuota: IRemainingRequests | null;
|
||||
|
@ -49,6 +50,10 @@ export interface IWizardUserResult {
|
|||
errors: string[];
|
||||
}
|
||||
|
||||
export interface IStreamingCountries {
|
||||
code: string;
|
||||
}
|
||||
|
||||
export enum UserType {
|
||||
LocalUser = 1,
|
||||
PlexUser = 2,
|
||||
|
|
|
@ -1,13 +1,27 @@
|
|||
<div *ngIf="movie">
|
||||
<span *ngIf="movie.voteAverage" matTooltip="{{'MediaDetails.Votes' | translate }} {{movie.voteCount | thousandShort: 1}}">
|
||||
<span *ngIf="movie.voteAverage"
|
||||
matTooltip="{{'MediaDetails.Votes' | translate }} {{movie.voteCount | thousandShort: 1}}">
|
||||
<img class="rating-small" src="{{baseUrl}}/images/tmdb-logo.svg"> {{movie.voteAverage | number:'1.0-1'}}/10
|
||||
</span>
|
||||
<span *ngIf="ratings?.critics_rating && ratings?.critics_score">
|
||||
<img class="rating-small" src="{{baseUrl}}/images/{{ratings.critics_rating === 'Rotten' ? 'rotten-rotten.svg' : 'rotten-fresh.svg'}}"> {{ratings.critics_score}}%
|
||||
<img class="rating-small"
|
||||
src="{{baseUrl}}/images/{{ratings.critics_rating === 'Rotten' ? 'rotten-rotten.svg' : 'rotten-fresh.svg'}}">
|
||||
{{ratings.critics_score}}%
|
||||
</span>
|
||||
<span *ngIf="ratings?.audience_rating && ratings?.audience_score">
|
||||
<img class="rating-small" src="{{baseUrl}}/images/{{ratings.audience_rating === 'Upright' ? 'rotten-audience-fresh.svg' : 'rotten-audience-rotten.svg'}}"> {{ratings.audience_score}}%
|
||||
<img class="rating-small"
|
||||
src="{{baseUrl}}/images/{{ratings.audience_rating === 'Upright' ? 'rotten-audience-fresh.svg' : 'rotten-audience-rotten.svg'}}">
|
||||
{{ratings.audience_score}}%
|
||||
</span>
|
||||
<div *ngIf="streams?.length > 0">
|
||||
<hr>
|
||||
<strong>{{'MediaDetails.StreamingOn' | translate }}:</strong>
|
||||
<div>
|
||||
<span *ngFor="let stream of streams">
|
||||
<img class="stream-small" [matTooltip]="stream.streamingProvider" src="https://image.tmdb.org/t/p/original{{stream.logo}}">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
<strong>{{'MediaDetails.Status' | translate }}:</strong>
|
||||
|
|
|
@ -4,6 +4,7 @@ import { IMovieRequests } from "../../../../interfaces";
|
|||
import { SearchV2Service } from "../../../../services/searchV2.service";
|
||||
import { IMovieRatings } from "../../../../interfaces/IRatings";
|
||||
import { APP_BASE_HREF } from "@angular/common";
|
||||
import { IStreamingData } from "../../../../interfaces/IStreams";
|
||||
@Component({
|
||||
templateUrl: "./movie-information-panel.component.html",
|
||||
styleUrls: ["../../../media-details.component.scss"],
|
||||
|
@ -19,9 +20,12 @@ export class MovieInformationPanelComponent implements OnInit {
|
|||
@Input() public advancedOptions: boolean;
|
||||
|
||||
public ratings: IMovieRatings;
|
||||
public streams: IStreamingData[];
|
||||
|
||||
public ngOnInit() {
|
||||
this.searchService.getRottenMovieRatings(this.movie.title, +this.movie.releaseDate.toString().substring(0,4))
|
||||
.subscribe(x => this.ratings = x);
|
||||
|
||||
this.searchService.getMovieStreams(this.movie.id).subscribe(x => this.streams = x);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,15 @@
|
|||
<img class="rating-small" src="{{baseUrl}}/images/{{ratings.class === 'rotten' ? 'rotten-rotten.svg' : 'rotten-fresh.svg'}}"> {{ratings.score}}%
|
||||
</span>
|
||||
|
||||
<div *ngIf="streams?.length > 0">
|
||||
<hr>
|
||||
<strong>{{'MediaDetails.StreamingOn' | translate }}:</strong>
|
||||
<div>
|
||||
<span *ngFor="let stream of streams">
|
||||
<img class="stream-small" [matTooltip]="stream.streamingProvider" src="https://image.tmdb.org/t/p/original{{stream.logo}}">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div *ngIf="tv.status">
|
||||
<strong>{{'MediaDetails.Status' | translate }}:</strong>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Component, ViewEncapsulation, Input, OnInit } from "@angular/core";
|
|||
import { ITvRequests } from "../../../../../interfaces";
|
||||
import { ITvRatings } from "../../../../../interfaces/IRatings";
|
||||
import { ISearchTvResultV2 } from "../../../../../interfaces/ISearchTvResultV2";
|
||||
import { IStreamingData } from "../../../../../interfaces/IStreams";
|
||||
import { SearchV2Service } from "../../../../../services";
|
||||
|
||||
@Component({
|
||||
|
@ -19,6 +20,7 @@ export class TvInformationPanelComponent implements OnInit {
|
|||
@Input() public advancedOptions: boolean;
|
||||
|
||||
public ratings: ITvRatings;
|
||||
public streams: IStreamingData[];
|
||||
public seasonCount: number;
|
||||
public totalEpisodes: number = 0;
|
||||
public nextEpisode: any;
|
||||
|
@ -26,6 +28,8 @@ export class TvInformationPanelComponent implements OnInit {
|
|||
public ngOnInit(): void {
|
||||
this.searchService.getRottenTvRatings(this.tv.title, +this.tv.firstAired.toString().substring(0,4))
|
||||
.subscribe(x => this.ratings = x);
|
||||
|
||||
this.searchService.getTvStreams(+this.tv.theTvDbId, this.tv.id).subscribe(x => this.streams = x);
|
||||
this.tv.seasonRequests.forEach(season => {
|
||||
this.totalEpisodes = this.totalEpisodes + season.episodes.length;
|
||||
});
|
||||
|
|
|
@ -231,3 +231,9 @@
|
|||
.rating-small {
|
||||
width: 1.3em;
|
||||
}
|
||||
.stream-small {
|
||||
width: 3em;
|
||||
border-radius: 1em;
|
||||
margin-right: 10px;
|
||||
margin-top: 5px;
|
||||
}
|
|
@ -4,7 +4,7 @@ import { Injectable, Inject } from "@angular/core";
|
|||
import { HttpClient } from "@angular/common/http";
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
import { ICheckbox, ICreateWizardUser, IIdentityResult, INotificationPreferences, IResetPasswordToken, IUpdateLocalUser, IUser, IUserDropdown, IWizardUserResult } from "../interfaces";
|
||||
import { ICheckbox, ICreateWizardUser, IIdentityResult, INotificationPreferences, IResetPasswordToken, IStreamingCountries, IUpdateLocalUser, IUser, IUserDropdown, IWizardUserResult } from "../interfaces";
|
||||
import { ServiceHelpers } from "./service.helpers";
|
||||
|
||||
@Injectable()
|
||||
|
@ -87,4 +87,12 @@ export class IdentityService extends ServiceHelpers {
|
|||
public updateLanguage(lang: string): Observable<null> {
|
||||
return this.http.post<any>(`${this.url}language`, {lang: lang}, {headers: this.headers});
|
||||
}
|
||||
|
||||
public getSupportedStreamingCountries(): Observable<string[]> {
|
||||
return this.http.get<string[]>(`${this.url}streamingcountry`, {headers: this.headers});
|
||||
}
|
||||
|
||||
public updateStreamingCountry(code: string): Observable<null> {
|
||||
return this.http.post<any>(`${this.url}streamingcountry`, {code: code}, {headers: this.headers});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import { ISearchTvResultV2, IMovieCollectionsViewModel, IActorCredits } from "..
|
|||
import { IArtistSearchResult, IAlbumArt } from "../interfaces/IMusicSearchResultV2";
|
||||
import { SearchFilter } from "../my-nav/SearchFilter";
|
||||
import { IMovieRatings, ITvRatings } from "../interfaces/IRatings";
|
||||
import { IStreamingData } from "../interfaces/IStreams";
|
||||
|
||||
@Injectable()
|
||||
export class SearchV2Service extends ServiceHelpers {
|
||||
|
@ -131,4 +132,12 @@ export class SearchV2Service extends ServiceHelpers {
|
|||
return this.http.get<ITvRatings>(`${this.url}/ratings/tv/${name}/${year}`);
|
||||
}
|
||||
|
||||
public getMovieStreams(theMovieDbId: number): Observable<IStreamingData[]> {
|
||||
return this.http.get<IStreamingData[]>(`${this.url}/stream/movie/${theMovieDbId}`);
|
||||
}
|
||||
|
||||
public getTvStreams(theTvDbId: number, tvMaze: number): Observable<IStreamingData[]> {
|
||||
return this.http.get<IStreamingData[]>(`${this.url}/stream/tv/${theTvDbId}/${tvMaze}`);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ import { EpisodeRequestComponent } from "./episode-request/episode-request.compo
|
|||
MatSnackBarModule,
|
||||
],
|
||||
entryComponents: [
|
||||
EpisodeRequestComponent
|
||||
EpisodeRequestComponent,
|
||||
],
|
||||
exports: [
|
||||
TranslateModule,
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
|
||||
|
||||
<hr>
|
||||
<div class="row justify-content-md-center top-spacing">
|
||||
<div class="col-md">
|
||||
<div class="row top-spacing">
|
||||
<div class="col-4">
|
||||
<div>
|
||||
<small>{{'UserPreferences.LanguageDescription' | translate}}</small>
|
||||
<br>
|
||||
<mat-form-field>
|
||||
<mat-label [translate]="'UserPreferences.OmbiLanguage'"></mat-label>
|
||||
<mat-select [(value)]="selectedLang" (selectionChange)="languageSelected();">
|
||||
|
@ -19,8 +21,32 @@
|
|||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md">
|
||||
<div class="col-1"></div>
|
||||
<div class="col-7">
|
||||
<mat-label [translate]="'UserPreferences.MobileQRCode'"></mat-label>
|
||||
<qrcode *ngIf="qrCodeEnabled" [qrdata]="qrCode" [size]="256" [level]="'L'"></qrcode>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<div>
|
||||
<small>{{'UserPreferences.StreamingCountryDescription' | translate}}</small>
|
||||
<br>
|
||||
<mat-form-field>
|
||||
<mat-label [translate]="'UserPreferences.StreamingCountry'"></mat-label>
|
||||
<mat-select [(value)]="selectedCountry" (selectionChange)="countrySelected();">
|
||||
<mat-option *ngFor="let value of countries" [value]="value">
|
||||
{{value}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
|
@ -3,7 +3,7 @@ import { AuthService } from "../../../auth/auth.service";
|
|||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { AvailableLanguages, ILanguage } from "./user-preference.constants";
|
||||
import { StorageService } from "../../../shared/storage/storage-service";
|
||||
import { IdentityService, SettingsService } from "../../../services";
|
||||
import { IdentityService, NotificationService, SettingsService } from "../../../services";
|
||||
import { IUser } from "../../../interfaces";
|
||||
|
||||
@Component({
|
||||
|
@ -17,12 +17,14 @@ export class UserPreferenceComponent implements OnInit {
|
|||
public availableLanguages = AvailableLanguages;
|
||||
public qrCode: string;
|
||||
public qrCodeEnabled: boolean;
|
||||
public countries: string[];
|
||||
public selectedCountry: string;
|
||||
|
||||
private user: IUser;
|
||||
|
||||
constructor(private authService: AuthService,
|
||||
private readonly translate: TranslateService,
|
||||
private storage: StorageService,
|
||||
private readonly notification: NotificationService,
|
||||
private readonly identityService: IdentityService,
|
||||
private readonly settingsService: SettingsService) { }
|
||||
|
||||
|
@ -33,6 +35,8 @@ export class UserPreferenceComponent implements OnInit {
|
|||
}
|
||||
const customization = await this.settingsService.getCustomization().toPromise();
|
||||
|
||||
this.selectedLang = this.translate.currentLang;
|
||||
|
||||
const accessToken = await this.identityService.getAccessToken().toPromise();
|
||||
this.qrCode = `${customization.applicationUrl}|${accessToken}`;
|
||||
|
||||
|
@ -43,14 +47,18 @@ export class UserPreferenceComponent implements OnInit {
|
|||
}
|
||||
|
||||
this.user = await this.identityService.getUser().toPromise();
|
||||
if (this.user.language) {
|
||||
this.selectedLang = this.user.language;
|
||||
}
|
||||
this.selectedCountry = this.user.streamingCountry;
|
||||
this.identityService.getSupportedStreamingCountries().subscribe(x => this.countries = x);
|
||||
|
||||
}
|
||||
|
||||
public languageSelected() {
|
||||
this.identityService.updateLanguage(this.selectedLang).subscribe();
|
||||
this.identityService.updateLanguage(this.selectedLang).subscribe(x => this.notification.success(this.translate.instant("UserPreferences.Updated")));
|
||||
this.translate.use(this.selectedLang);
|
||||
}
|
||||
|
||||
public countrySelected() {
|
||||
this.identityService.updateStreamingCountry(this.selectedCountry).subscribe(x => this.notification.success(this.translate.instant("UserPreferences.Updated")));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,14 @@
|
|||
<input matInput placeholder="Email Address" type="email" [(ngModel)]="user.emailAddress">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field>
|
||||
<mat-label [translate]="'UserPreferences.StreamingCountry'"></mat-label>
|
||||
<mat-select [(value)]="user.streamingCountry">
|
||||
<mat-option *ngFor="let value of countries" [value]="value">
|
||||
{{value}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<div>
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="Password" type="password" [(ngModel)]="user.password" required>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Location } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { AfterViewInit, Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { ICheckbox, INotificationAgent, INotificationPreferences, IRadarrProfile, IRadarrRootFolder, ISonarrProfile, ISonarrRootFolder, IUser, UserType } from "../interfaces";
|
||||
|
@ -25,6 +25,8 @@ export class UserManagementUserComponent implements OnInit {
|
|||
public NotificationAgent = INotificationAgent;
|
||||
public edit: boolean;
|
||||
|
||||
public countries: string[];
|
||||
|
||||
constructor(private identityService: IdentityService,
|
||||
private notificationService: MessageService,
|
||||
private router: Router,
|
||||
|
@ -45,6 +47,8 @@ export class UserManagementUserComponent implements OnInit {
|
|||
}
|
||||
|
||||
public ngOnInit() {
|
||||
|
||||
this.identityService.getSupportedStreamingCountries().subscribe(x => this.countries = x);
|
||||
this.identityService.getAllAvailableClaims().subscribe(x => this.availableClaims = x);
|
||||
if(this.edit) {
|
||||
this.identityService.getNotificationPreferencesForUser(this.userId).subscribe(x => this.notificationPreferences = x);
|
||||
|
@ -74,6 +78,7 @@ export class UserManagementUserComponent implements OnInit {
|
|||
episodeRequestQuota: null,
|
||||
movieRequestQuota: null,
|
||||
language: null,
|
||||
streamingCountry: "US",
|
||||
userQualityProfiles: {
|
||||
radarrQualityProfile: 0,
|
||||
radarrRootPath: 0,
|
||||
|
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Plex;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Attributes;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Engine;
|
||||
|
@ -159,7 +160,8 @@ namespace Ombi.Controllers.V1
|
|||
UserName = plexUser.user.username,
|
||||
UserType = UserType.PlexUser,
|
||||
Email = plexUser.user.email,
|
||||
ProviderUserId = plexUser.user.id
|
||||
ProviderUserId = plexUser.user.id,
|
||||
StreamingCountry = "US" // Default
|
||||
};
|
||||
|
||||
await _userManagementSettings.SaveSettingsAsync(new UserManagementSettings
|
||||
|
@ -173,7 +175,8 @@ namespace Ombi.Controllers.V1
|
|||
var userToCreate = new OmbiUser
|
||||
{
|
||||
UserName = user.Username,
|
||||
UserType = UserType.LocalUser
|
||||
UserType = UserType.LocalUser,
|
||||
StreamingCountry = "US"
|
||||
};
|
||||
|
||||
return await SaveWizardUser(user, userToCreate);
|
||||
|
@ -329,6 +332,32 @@ namespace Ombi.Controllers.V1
|
|||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the supported country codes that we have streaming data for
|
||||
/// </summary>
|
||||
[HttpGet("streamingcountry")]
|
||||
[Authorize]
|
||||
public IActionResult GetSupportedStreamingCountries()
|
||||
{
|
||||
var resultsProp = typeof(Results).GetProperties();
|
||||
return Json(resultsProp.Select(x => x.Name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current users country streaming preference
|
||||
/// </summary>
|
||||
[HttpPost("streamingcountry")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> SetCurrentUserCountryStreaming([FromBody] CountryStreamingPreference model)
|
||||
{
|
||||
var username = User.Identity.Name.ToUpper();
|
||||
var user = await UserManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username);
|
||||
user.StreamingCountry = model.Code;
|
||||
|
||||
await UserManager.UpdateAsync(user);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user by the user id.
|
||||
/// </summary>
|
||||
|
@ -358,7 +387,8 @@ namespace Ombi.Controllers.V1
|
|||
EpisodeRequestLimit = user.EpisodeRequestLimit ?? 0,
|
||||
MovieRequestLimit = user.MovieRequestLimit ?? 0,
|
||||
MusicRequestLimit = user.MusicRequestLimit ?? 0,
|
||||
Language = user.Language
|
||||
Language = user.Language,
|
||||
StreamingCountry = user.StreamingCountry
|
||||
};
|
||||
|
||||
foreach (var role in userRoles)
|
||||
|
@ -437,6 +467,7 @@ namespace Ombi.Controllers.V1
|
|||
EpisodeRequestLimit = user.EpisodeRequestLimit,
|
||||
MusicRequestLimit = user.MusicRequestLimit,
|
||||
UserAccessToken = Guid.NewGuid().ToString("N"),
|
||||
StreamingCountry = user.StreamingCountry.HasValue() ? user.StreamingCountry : "US"
|
||||
};
|
||||
var userResult = await UserManager.CreateAsync(ombiUser, user.Password);
|
||||
|
||||
|
@ -594,6 +625,10 @@ namespace Ombi.Controllers.V1
|
|||
user.MovieRequestLimit = ui.MovieRequestLimit;
|
||||
user.EpisodeRequestLimit = ui.EpisodeRequestLimit;
|
||||
user.MusicRequestLimit = ui.MusicRequestLimit;
|
||||
if (ui.StreamingCountry.HasValue())
|
||||
{
|
||||
user.StreamingCountry = ui.StreamingCountry;
|
||||
}
|
||||
var updateResult = await UserManager.UpdateAsync(user);
|
||||
if (!updateResult.Succeeded)
|
||||
{
|
||||
|
@ -739,7 +774,7 @@ namespace Ombi.Controllers.V1
|
|||
[HttpPost("reset")]
|
||||
[AllowAnonymous]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public async Task<OmbiIdentityResult> SubmitResetPassword([FromBody]SubmitPasswordReset email)
|
||||
public async Task<OmbiIdentityResult> SubmitResetPassword([FromBody] SubmitPasswordReset email)
|
||||
{
|
||||
// Check if account exists
|
||||
var user = await UserManager.FindByEmailAsync(email.Email);
|
||||
|
@ -817,7 +852,7 @@ namespace Ombi.Controllers.V1
|
|||
[HttpPost("resetpassword")]
|
||||
[AllowAnonymous]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public async Task<OmbiIdentityResult> ResetPassword([FromBody]ResetPasswordToken token)
|
||||
public async Task<OmbiIdentityResult> ResetPassword([FromBody] ResetPasswordToken token)
|
||||
{
|
||||
var user = await UserManager.FindByEmailAsync(token.Email);
|
||||
|
||||
|
|
|
@ -420,5 +420,20 @@ namespace Ombi.Controllers.V2
|
|||
return _rottenTomatoesApi.GetTvRatings(name, year);
|
||||
}
|
||||
|
||||
[HttpGet("stream/movie/{movieDbId}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesDefaultResponseType]
|
||||
public Task<IEnumerable<StreamingData>> GetMovieStreams(int movieDBId)
|
||||
{
|
||||
return _movieEngineV2.GetStreamInformation(movieDBId, HttpContext.RequestAborted);
|
||||
}
|
||||
|
||||
[HttpGet("stream/tv/{tvdbId}/{tvMaze}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesDefaultResponseType]
|
||||
public Task<IEnumerable<StreamingData>> GetTvStreams(int tvdbId, int tvMaze)
|
||||
{
|
||||
return _tvEngineV2.GetStreamInformation(tvdbId, tvMaze, HttpContext.RequestAborted);
|
||||
}
|
||||
}
|
||||
}
|
7
src/Ombi/Models/Identity/CountryStreamingPreference.cs
Normal file
7
src/Ombi/Models/Identity/CountryStreamingPreference.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Ombi.Models.Identity
|
||||
{
|
||||
public class CountryStreamingPreference
|
||||
{
|
||||
public string Code { get; set; }
|
||||
}
|
||||
}
|
|
@ -275,7 +275,8 @@
|
|||
"SonarrConfiguration": "Sonarr Configuration",
|
||||
"RadarrConfiguration": "Radarr Configuration",
|
||||
"RequestOnBehalf": "Request on behalf of",
|
||||
"PleaseSelectUser": "Please select a user"
|
||||
"PleaseSelectUser": "Please select a user",
|
||||
"StreamingOn": "Streaming On"
|
||||
},
|
||||
"Discovery": {
|
||||
"PopularTab": "Popular",
|
||||
|
@ -300,6 +301,11 @@
|
|||
"UserPreferences": {
|
||||
"Welcome": "Welcome {{username}}!",
|
||||
"OmbiLanguage": "Language",
|
||||
"DarkMode": "Dark Mode"
|
||||
"DarkMode": "Dark Mode",
|
||||
"Updated": "Successfully Updated",
|
||||
"StreamingCountry":"Streaming Country",
|
||||
"StreamingCountryDescription": "This is the country code that we will display streaming information for. If you are in the US please select US and you will have US related streaming information.",
|
||||
"LanguageDescription": "This is the language you would like the Ombi interface to be displayed in.",
|
||||
"MobileQRCode":"Mobile QR Code"
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue