Merge pull request #1 from tidusjar/feature/v4

syncing
pull/3745/head
Twan Ariens 4 years ago committed by GitHub
commit 8572d04caf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -48,6 +48,7 @@ stages:
- stage: deploy
jobs:
- job:
condition: and(succeeded(), eq(variables.isMain, true))
steps:
- task: DownloadPipelineArtifact@2
inputs:
@ -90,4 +91,3 @@ stages:
isPreRelease: true
changeLogCompareToRelease: 'lastNonDraftRelease'
changeLogType: 'commitBased'
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/feature/v4'))

@ -4,7 +4,7 @@ variables:
- name: "vmImage"
value: "ubuntu-latest"
- name: "Solution"
value: "**/*.sln"
@ -24,4 +24,7 @@ variables:
value: "$(Build.SourcesDirectory)/src/Ombi/ClientApp/"
- name: "BuildVersion"
value: "4.0.$(Build.BuildId)"
value: "4.0.$(Build.BuildId)"
- name: isMain
value: $[eq(variables['Build.SourceBranch'], 'refs/heads/feature/v4')]

@ -29,6 +29,7 @@ If applicable, a snippet of the logs that seems relevant to the bug if present.
**Ombi Version (please complete the following information):**
- Version [e.g. 3.0.1158]
- Media Server [e.g. Plex]
- Database Type: SQLite (Please change if using MySQL)
**Additional context**
Add any other context about the problem here.

@ -44,7 +44,13 @@ namespace Ombi.Api.Plex.Models
public string grandparentTheme { get; set; }
public string chapterSource { get; set; }
public Medium[] Media { get; set; }
public PlexGuids[] Guid { get; set; }
// public Director[] Director { get; set; }
// public Writer[] Writer { get; set; }
}
public class PlexGuids
{
public string Id { get; set; }
}
}

@ -41,6 +41,37 @@ namespace Ombi.Helpers.Tests
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");
yield return new TestCaseData("com.plexapp.agents.xbmcnfotv://153021/2/1?lang=xn", ProviderIdType.TvDb).Returns("153021").SetName("xmbc agent, tv episode");
yield return new TestCaseData("com.plexapp.agents.xbmcnfotv://153021?lang=xn", ProviderIdType.TvDb).Returns("153021").SetName("xmbc agent, tv show");
yield return new TestCaseData("tmdb://610201", ProviderIdType.MovieDb).Returns("610201").SetName("Themoviedb new plex format");
}
}
[TestCaseSource(nameof(ProviderIdGuidDataV2))]
public void GetProviderIdsFromMetadataTests(string guidInput, ProviderId expected)
{
var param = guidInput.Split('|', StringSplitOptions.RemoveEmptyEntries);
var result = PlexHelper.GetProviderIdsFromMetadata(param);
Assert.AreEqual(expected.ImdbId, result.ImdbId);
Assert.AreEqual(expected.TheMovieDb, result.TheMovieDb);
Assert.AreEqual(expected.TheTvDb, result.TheTvDb);
}
public static IEnumerable<TestCaseData> ProviderIdGuidDataV2
{
get
{
yield return new TestCaseData("plex://movie/5e1632df2d4d84003e48e54e|imdb://tt9178402|tmdb://610201", new ProviderId { ImdbId = "tt9178402", TheMovieDb = "610201" }).SetName("V2 Regular Plex Id");
yield return new TestCaseData("plex://movie/5d7768253c3c2a001fbcab72|imdb://tt0119567|tmdb://330", new ProviderId { ImdbId = "tt0119567", TheMovieDb = "330" }).SetName("V2 Regular Plex Id Another");
yield return new TestCaseData("plex://movie/5d7768253c3c2a001fbcab72|imdb://tt0119567", new ProviderId { ImdbId = "tt0119567" }).SetName("V2 Regular Plex Id Single Imdb");
yield return new TestCaseData("plex://movie/5d7768253c3c2a001fbcab72|tmdb://330", new ProviderId { TheMovieDb = "330" }).SetName("V2 Regular Plex Id Single Tmdb");
yield return new TestCaseData("com.plexapp.agents.thetvdb://269586/2/8?lang=en", new ProviderId { TheTvDb = "269586" }).SetName("V2 Regular TvDb Id");
yield return new TestCaseData("com.plexapp.agents.themoviedb://390043?lang=en", new ProviderId { TheMovieDb = "390043" }).SetName("V2 Regular MovieDb Id");
yield return new TestCaseData("com.plexapp.agents.imdb://tt2543164?lang=en", new ProviderId { ImdbId = "tt2543164" }).SetName("V2 Regular Imdb Id");
yield return new TestCaseData("com.plexapp.agents.agent47://tt2543456?lang=en", new ProviderId { ImdbId = "tt2543456" }).SetName("V2 Unknown IMDB agent");
yield return new TestCaseData("com.plexapp.agents.agent47://456822/1/1?lang=en", new ProviderId { TheTvDb = "456822" }).SetName("V2 Unknown TvDb agent");
yield return new TestCaseData("com.plexapp.agents.agent47://456822/999/999?lang=en", new ProviderId { TheTvDb = "456822" }).SetName("V2 Unknown TvDb agent, large episode and season");
yield return new TestCaseData("com.plexapp.agents.xbmcnfotv://153021/2/1?lang=xn", new ProviderId { TheTvDb = "153021" }).SetName("V2 xmbc agent, tv episode");
yield return new TestCaseData("com.plexapp.agents.xbmcnfotv://153021?lang=xn", new ProviderId { TheTvDb = "153021" }).SetName("V2 xmbc agent, tv show");
}
}

@ -41,6 +41,7 @@ namespace Ombi.Helpers
//com.plexapp.agents.thetvdb://269586/2/8?lang=en
//com.plexapp.agents.themoviedb://390043?lang=en
//com.plexapp.agents.imdb://tt2543164?lang=en
//plex://movie/5e1632df2d4d84003e48e54e
// https://github.com/tidusjar/Ombi/issues/3277
if (string.IsNullOrEmpty(guid))
{
@ -57,7 +58,7 @@ namespace Ombi.Helpers
TheTvDb = guidSplit[1]
};
}
if (guid.Contains("themoviedb", CompareOptions.IgnoreCase))
if (guid.Contains("themoviedb", CompareOptions.IgnoreCase) || guid.Contains("tmdb", CompareOptions.IgnoreCase))
{
return new ProviderId
{
@ -71,6 +72,13 @@ namespace Ombi.Helpers
ImdbId = guidSplit[1]
};
}
if (guid.Contains("plex://", CompareOptions.IgnoreCase))
{
return new ProviderId
{
Plex = true
};
}
var imdbRegex = new Regex(ImdbMatchExpression, RegexOptions.Compiled);
var tvdbRegex = new Regex(TvDbIdMatchExpression, RegexOptions.Compiled);
@ -102,6 +110,37 @@ namespace Ombi.Helpers
$"https://app.plex.tv/web/app#!/server/{machineId}/details?key=library%2Fmetadata%2F{mediaId}";
return url;
}
public static ProviderId GetProviderIdsFromMetadata(params string[] guids)
{
var providerIds = new ProviderId();
foreach (var guid in guids)
{
var provider = GetProviderIdFromPlexGuid(guid);
if (provider.Type == ProviderType.Plex)
{
// There are more guids!
continue;
}
switch (provider.Type)
{
case ProviderType.ImdbId:
providerIds.ImdbId = provider.ImdbId;
break;
case ProviderType.TheMovieDbId:
providerIds.TheMovieDb = provider.TheMovieDb;
break;
case ProviderType.TvDbId:
providerIds.TheTvDb = provider.TheTvDb;
break;
default:
throw new ArgumentOutOfRangeException(nameof(provider.Type));
}
}
return providerIds;
}
}
public class ProviderId
@ -109,6 +148,7 @@ namespace Ombi.Helpers
public string TheTvDb { get; set; }
public string TheMovieDb { get; set; }
public string ImdbId { get; set; }
public bool Plex { get; set; }
public ProviderType Type
{
@ -126,6 +166,10 @@ namespace Ombi.Helpers
{
return ProviderType.TvDbId;
}
if (Plex)
{
return ProviderType.Plex;
}
return ProviderType.ImdbId;
}
}
@ -135,6 +179,7 @@ namespace Ombi.Helpers
{
ImdbId,
TheMovieDbId,
TvDbId
TvDbId,
Plex
}
}

@ -107,11 +107,20 @@ namespace Ombi.Notifications.Agents
var fields = new List<DiscordField>();
if (model.Data.TryGetValue("RequestedUser", out var requestedUser))
if (model.Data.TryGetValue("Alias", out var alias))
{
if (requestedUser.HasValue())
if (alias.HasValue())
{
fields.Add(new DiscordField { name = "Requested By", value = requestedUser, inline = true });
fields.Add(new DiscordField { name = "Requested By", value = alias, inline = true });
}
} else
{
if (model.Data.TryGetValue("RequestedUser", out var requestedUser))
{
if (requestedUser.HasValue())
{
fields.Add(new DiscordField { name = "Requested By", value = requestedUser, inline = true });
}
}
}
if (model.Data.TryGetValue("DenyReason", out var denyReason))

@ -7,10 +7,12 @@ using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Core;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Hubs;
using Ombi.Notifications.Models;
using Ombi.Schedule.Jobs.Plex.Models;
using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities;
using Ombi.Store.Repository;
using Ombi.Store.Repository.Requests;
@ -20,13 +22,26 @@ namespace Ombi.Schedule.Jobs.Radarr
{
public class ArrAvailabilityChecker : IArrAvailabilityChecker
{
private readonly IExternalRepository<RadarrCache> _radarrRepo;
private readonly IExternalRepository<SonarrCache> _sonarrRepo;
private readonly ILogger<ArrAvailabilityChecker> _logger;
private readonly ISettingsService<RadarrSettings> _radarrSettings;
private readonly ISettingsService<SonarrSettings> _sonarrSettings;
private readonly IExternalRepository<SonarrEpisodeCache> _sonarrEpisodeRepo;
private readonly INotificationHelper _notification;
private readonly IHubContext<NotificationHub> _hub;
private readonly ITvRequestRepository _tvRequest;
private readonly IMovieRequestRepository _movies;
public ArrAvailabilityChecker(
IExternalRepository<RadarrCache> radarrRepo,
IExternalRepository<SonarrCache> sonarrRepo,
IExternalRepository<SonarrEpisodeCache> sonarrEpisodeRepo,
INotificationHelper notification, IHubContext<NotificationHub> hub,
ITvRequestRepository tvRequest, IMovieRequestRepository movies,
ILogger<ArrAvailabilityChecker> log)
ILogger<ArrAvailabilityChecker> log,
ISettingsService<RadarrSettings> radarrSettings,
ISettingsService<SonarrSettings> sonarrSettings)
{
_radarrRepo = radarrRepo;
_sonarrRepo = sonarrRepo;
@ -36,21 +51,23 @@ namespace Ombi.Schedule.Jobs.Radarr
_tvRequest = tvRequest;
_movies = movies;
_logger = log;
_radarrSettings = radarrSettings;
_sonarrSettings = sonarrSettings;
}
private readonly IExternalRepository<RadarrCache> _radarrRepo;
private readonly IExternalRepository<SonarrCache> _sonarrRepo;
private readonly ILogger<ArrAvailabilityChecker> _logger;
private readonly IExternalRepository<SonarrEpisodeCache> _sonarrEpisodeRepo;
private readonly INotificationHelper _notification;
private readonly IHubContext<NotificationHub> _hub;
private readonly ITvRequestRepository _tvRequest;
private readonly IMovieRequestRepository _movies;
public async Task Execute(IJobExecutionContext job)
{
await ProcessMovies();
await ProcessTvShows();
var radarrSettings = await _radarrSettings.GetSettingsAsync();
var sonarrSettings = await _sonarrSettings.GetSettingsAsync();
if (radarrSettings.ScanForAvailability)
{
await ProcessMovies();
}
if (sonarrSettings.ScanForAvailability)
{
await ProcessTvShows();
}
}
private async Task ProcessMovies()

@ -281,9 +281,21 @@ namespace Ombi.Schedule.Jobs.Plex
Logger.LogDebug("Adding movie {0}", movie.title);
var metaData = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
movie.ratingKey);
var providerIds = PlexHelper.GetProviderIdFromPlexGuid(metaData.MediaContainer.Metadata
.FirstOrDefault()
.guid);
var meta = metaData.MediaContainer.Metadata.FirstOrDefault();
var guids = new List<string>
{
meta.guid
};
if (meta.Guid != null)
{
foreach (var g in meta.Guid)
{
guids.Add(g.Id);
}
}
var providerIds = PlexHelper.GetProviderIdsFromMetadata(guids.ToArray());
var item = new PlexServerContent
{
@ -296,15 +308,15 @@ namespace Ombi.Schedule.Jobs.Plex
Seasons = new List<PlexSeasonsContent>(),
Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty
};
if (providerIds.Type == ProviderType.ImdbId)
if (providerIds.ImdbId.HasValue())
{
item.ImdbId = providerIds.ImdbId;
}
if (providerIds.Type == ProviderType.TheMovieDbId)
if (providerIds.TheMovieDb.HasValue())
{
item.TheMovieDbId = providerIds.TheMovieDb;
}
if (providerIds.Type == ProviderType.TvDbId)
if (providerIds.TheTvDb.HasValue())
{
item.TvDbId = providerIds.TheTvDb;
}
@ -563,20 +575,31 @@ namespace Ombi.Schedule.Jobs.Plex
private static void GetProviderIds(PlexMetadata showMetadata, PlexServerContent existingContent)
{
var metadata = showMetadata.MediaContainer.Metadata.FirstOrDefault();
var guids = new List<string>
{
metadata.guid
};
if (metadata.Guid != null)
{
foreach (var g in metadata.Guid)
{
guids.Add(g.Id);
}
}
var providerIds =
PlexHelper.GetProviderIdFromPlexGuid(showMetadata.MediaContainer.Metadata.FirstOrDefault()
.guid);
if (providerIds.Type == ProviderType.ImdbId)
PlexHelper.GetProviderIdsFromMetadata(guids.ToArray());
if (providerIds.ImdbId.HasValue())
{
existingContent.ImdbId = providerIds.ImdbId;
}
if (providerIds.Type == ProviderType.TheMovieDbId)
if (providerIds.TheMovieDb.HasValue())
{
existingContent.TheMovieDbId = providerIds.TheMovieDb;
}
if (providerIds.Type == ProviderType.TvDbId)
if (providerIds.TheTvDb.HasValue())
{
existingContent.TvDbId = providerIds.TheTvDb;
}

@ -10,5 +10,6 @@ namespace Ombi.Settings.Settings.Models.External
public string DefaultRootPath { get; set; }
public bool AddOnly { get; set; }
public string MinimumAvailability { get; set; }
public bool ScanForAvailability { get; set; }
}
}

@ -20,5 +20,6 @@
public bool AddOnly { get; set; }
public bool V3 { get; set; }
public int LanguageProfile { get; set; }
public bool ScanForAvailability { get; set; }
}
}

@ -8,34 +8,34 @@ namespace Ombi.Store.Migrations.OmbiMySql
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"CREATE TABLE `MobileDevices` (
`Id` int NOT NULL AUTO_INCREMENT,
`Token` longtext CHARACTER SET utf8mb4 NULL,
`UserId` varchar(255) COLLATE utf8mb4_bin NOT NULL,
`AddedAt` datetime(6) NOT NULL,
CONSTRAINT `PK_MobileDevices` PRIMARY KEY (`Id`),
CONSTRAINT `FK_MobileDevices_AspNetUsers_UserId` FOREIGN KEY (`UserId`) REFERENCES `AspNetUsers` (`Id`) ON DELETE RESTRICT
);");
// migrationBuilder.Sql(@"CREATE TABLE `MobileDevices` (
// `Id` int NOT NULL AUTO_INCREMENT,
// `Token` longtext CHARACTER SET utf8mb4 NULL,
// `UserId` varchar(255) CHARACTER SET utf8mb4 NOT NULL,
// `AddedAt` datetime(6) NOT NULL,
// CONSTRAINT `PK_MobileDevices` PRIMARY KEY (`Id`),
// CONSTRAINT `FK_MobileDevices_AspNetUsers_UserId` FOREIGN KEY (`UserId`) REFERENCES `AspNetUsers` (`Id`) ON DELETE RESTRICT
//);");
//migrationBuilder.CreateTable(
// name: "MobileDevices",
// columns: table => new
// {
// Id = table.Column<int>(nullable: false).Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
// Token = table.Column<string>(maxLength: 256, nullable: true),
// UserId = table.Column<string>(maxLength: 255, nullable: false),
// AddedAt = table.Column<DateTime>(maxLength: 256, nullable: false),
// },
// constraints: table =>
// {
// table.PrimaryKey("PK_MobileDevices", x => x.Id);
// table.ForeignKey(
// name: "FK_MobileDevices_AspNetUsers_UserId",
// column: x => x.UserId,
// principalTable: "AspNetUsers",
// principalColumn: "Id",
// onDelete: ReferentialAction.Restrict);
// });
migrationBuilder.CreateTable(
name: "MobileDevices",
columns: table => new
{
Id = table.Column<int>(nullable: false).Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Token = table.Column<string>(maxLength: 256, nullable: true),
UserId = table.Column<string>(maxLength: 255, nullable: false),
AddedAt = table.Column<DateTime>(maxLength: 256, nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_MobileDevices", x => x.Id);
table.ForeignKey(
name: "FK_MobileDevices_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(

File diff suppressed because it is too large Load Diff

@ -20,18 +20,18 @@ namespace Ombi.Store.Migrations.OmbiMySql
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("Name")
.HasColumnType("varchar(256) CHARACTER SET utf8mb4")
.HasColumnType("varchar(256)")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasColumnType("varchar(256) CHARACTER SET utf8mb4")
.HasColumnType("varchar(256)")
.HasMaxLength(256);
b.HasKey("Id");
@ -50,14 +50,14 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -73,14 +73,14 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -92,17 +92,17 @@ namespace Ombi.Store.Migrations.OmbiMySql
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<string>("ProviderKey")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("LoginProvider", "ProviderKey");
@ -114,10 +114,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<string>("RoleId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("UserId", "RoleId");
@ -129,16 +129,16 @@ namespace Ombi.Store.Migrations.OmbiMySql
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<string>("LoginProvider")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<string>("Name")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<string>("Value")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.HasKey("UserId", "LoginProvider", "Name");
@ -161,10 +161,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("User")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.HasKey("Id");
@ -181,10 +181,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("datetime(6)");
b.Property<string>("Token")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -206,13 +206,13 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("tinyint(1)");
b.Property<string>("Message")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int>("NotificationType")
.HasColumnType("int");
b.Property<string>("Subject")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.HasKey("Id");
@ -229,10 +229,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("datetime(6)");
b.Property<string>("PlayerId")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -244,20 +244,20 @@ namespace Ombi.Store.Migrations.OmbiMySql
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("Alias")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("Email")
.HasColumnType("varchar(256) CHARACTER SET utf8mb4")
.HasColumnType("varchar(256)")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed")
@ -267,7 +267,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("Language")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<DateTime?>("LastLoggedIn")
.HasColumnType("datetime(6)");
@ -285,36 +285,36 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("NormalizedEmail")
.HasColumnType("varchar(256) CHARACTER SET utf8mb4")
.HasColumnType("varchar(256)")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasColumnType("varchar(256) CHARACTER SET utf8mb4")
.HasColumnType("varchar(256)")
.HasMaxLength(256);
b.Property<string>("PasswordHash")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("PhoneNumber")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("tinyint(1)");
b.Property<string>("ProviderUserId")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("SecurityStamp")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("UserAccessToken")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("UserName")
.HasColumnType("varchar(256) CHARACTER SET utf8mb4")
.HasColumnType("varchar(256)")
.HasMaxLength(256);
b.Property<int>("UserType")
@ -342,7 +342,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("datetime(6)");
b.Property<string>("AlbumId")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int>("ContentId")
.HasColumnType("int");
@ -377,7 +377,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("datetime(6)");
b.Property<string>("Error")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int>("RequestId")
.HasColumnType("int");
@ -406,7 +406,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -425,28 +425,28 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("tinyint(1)");
b.Property<string>("ArtistName")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<bool>("Available")
.HasColumnType("tinyint(1)");
b.Property<string>("Cover")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<bool?>("Denied")
.HasColumnType("tinyint(1)");
b.Property<string>("DeniedReason")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("Disk")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("ForeignAlbumId")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("ForeignArtistId")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<DateTime>("MarkedAsApproved")
.HasColumnType("datetime(6)");
@ -467,16 +467,16 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("RequestedByAlias")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<DateTime>("RequestedDate")
.HasColumnType("datetime(6)");
b.Property<string>("RequestedUserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<string>("Title")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.HasKey("Id");
@ -501,7 +501,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("tinyint(1)");
b.Property<string>("DeniedReason")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int?>("IssueId")
.HasColumnType("int");
@ -522,19 +522,19 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("RequestedByAlias")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<DateTime>("RequestedDate")
.HasColumnType("datetime(6)");
b.Property<string>("RequestedUserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<int>("SeriesType")
.HasColumnType("int");
b.Property<string>("Title")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.HasKey("Id");
@ -552,7 +552,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("Value")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.HasKey("Id");
@ -566,7 +566,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("Comment")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<DateTime>("Date")
.HasColumnType("datetime(6)");
@ -575,7 +575,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -596,7 +596,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int>("IssueCategoryId")
.HasColumnType("int");
@ -605,7 +605,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("ProviderId")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int?>("RequestId")
.HasColumnType("int");
@ -620,13 +620,13 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("Subject")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("UserReportedId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -652,25 +652,25 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("tinyint(1)");
b.Property<string>("Background")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<bool?>("Denied")
.HasColumnType("tinyint(1)");
b.Property<string>("DeniedReason")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<DateTime?>("DigitalReleaseDate")
.HasColumnType("datetime(6)");
b.Property<string>("ImdbId")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int?>("IssueId")
.HasColumnType("int");
b.Property<string>("LangCode")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<DateTime>("MarkedAsApproved")
.HasColumnType("datetime(6)");
@ -682,10 +682,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("datetime(6)");
b.Property<string>("Overview")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("PosterPath")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int>("QualityOverride")
.HasColumnType("int");
@ -697,25 +697,25 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("RequestedByAlias")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<DateTime>("RequestedDate")
.HasColumnType("datetime(6)");
b.Property<string>("RequestedUserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<int>("RootPathOverride")
.HasColumnType("int");
b.Property<string>("Status")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
b.Property<string>("Title")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.HasKey("Id");
@ -743,7 +743,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -759,16 +759,16 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("Background")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("ImdbId")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("Overview")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("PosterPath")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int?>("QualityOverride")
.HasColumnType("int");
@ -780,10 +780,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("Status")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<int>("TotalSeasons")
.HasColumnType("int");
@ -803,10 +803,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("Token")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -828,10 +828,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("tinyint(1)");
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<string>("Value")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.HasKey("Id");
@ -865,7 +865,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.HasKey("Id");
@ -893,7 +893,7 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("UserId")
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
.HasColumnType("varchar(255)");
b.Property<int>("VoteType")
.HasColumnType("int");
@ -930,10 +930,10 @@ namespace Ombi.Store.Migrations.OmbiMySql
.HasColumnType("int");
b.Property<string>("Title")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.Property<string>("Url")
.HasColumnType("longtext CHARACTER SET utf8mb4");
.HasColumnType("longtext");
b.HasKey("Id");

@ -170,7 +170,7 @@
<div>
<app-my-nav [showNav]="showNav" [isAdmin]="isAdmin" [applicationName]="applicationName" [username]="username" (logoutClick)="logOut();" (themeChange)="onSetTheme($event)">
<app-my-nav id="main-container" [showNav]="showNav" [isAdmin]="isAdmin" [applicationName]="applicationName" [username]="username" (logoutClick)="logOut();" (themeChange)="onSetTheme($event)">
</app-my-nav>

@ -17,13 +17,7 @@
font-weight: bold;
}
.grow {
transition: all .2s ease-in-out;
}
.grow:hover {
transform: scale(1.1);
}
h3 strong {
font-weight: bold;
}

@ -1,8 +1,9 @@
$ombi-primary:#3f3f3f;
$card-background: #2b2b2b;
#cardImage {
border-radius: 5px 5px 0px 0px;
height:75%;
height: 75%;
}
.dark-card {
@ -12,7 +13,7 @@ $card-background: #2b2b2b;
// Changed height to 100% to make all cards the same height
.card-spacing {
margin-top: 10%;
height:100%;
height: 100%;
}
@ -34,6 +35,7 @@ $border-width: 3px;
.requested {
border-bottom: $border-width #ffd740 solid;
}
.notrequested {
border-bottom: $border-width #303030 solid;
}
@ -42,14 +44,17 @@ $border-width: 3px;
text-align: center;
}
// Changed height to 100% to make all cards the same height
.grow {
transition: all .2s ease-in-out;
height:100%;
}
@media (min-width: 1025px) {
.grow:hover {
transform: scale(1.1);
// Changed height to 100% to make all cards the same height
.grow {
transition: all .2s ease-in-out;
height: 100%;
}
.grow:hover {
transform: scale(1.1);
}
}
::ng-deep mat-dialog-container.mat-dialog-container {
@ -61,21 +66,22 @@ $border-width: 3px;
/* Title adjust for the Discover page */
.mat-card-content h6 {
overflow:hidden;
white-space:nowrap;
font-weight:400;
font-size:1.1rem;
overflow: hidden;
white-space: nowrap;
font-weight: 400;
font-size: 1.1rem;
}
/* Summary adjust for Discover page */
.small, small {
font-size:0.8rem;
.small,
small {
font-size: 0.8rem;
}
@media (min-width: 2000px) {
#cardImage {
height:80%;
object-fit:cover;
display:block;
height: 80%;
object-fit: cover;
display: block;
}
}

@ -27,80 +27,83 @@
}
::ng-deep .mat-card-image {
height:75%;
object-fit:cover;
display:block;
height: 75%;
object-fit: cover;
display: block;
}
.card-spacing {
height:100%;
height: 100%;
}
.mat-card-content h6 {
overflow:hidden;
white-space:nowrap;
font-weight:500;
font-size:1.1rem;
overflow: hidden;
white-space: nowrap;
font-weight: 500;
font-size: 1.1rem;
}
@media (min-width: 300px) {
.small-middle-container {
margin: inherit;
}
.col-xl-2 {
flex: 0 0 100%;
max-width: 100%;
min-width: 100%;
}
.small-middle-container{
width:100%;
}
.btn-group {
width:100%;
width: 100%;
}
mat-button-base {
width:100%;
width: 100%;
}
.col{
.col {
padding-right: 10px !important;
padding-left:10px !important;
padding-left: 10px !important;
}
.row{
margin-left:0px;
.row {
margin-left: 0px;
}
.small-padding{
.small-padding {
padding-left: 5px !important;
padding-right: 0px !important;
height: 40em;
}
::ng-deep .mat-card-image {
height:85% !important;
height: 85% !important;
}
}
@media (min-width: 600px) {
.justify-content-md-center {
justify-content: center !important;
justify-content: center !important;
}
.small-middle-container{
width:auto;
.small-middle-container {
width: auto;
}
.btn-group {
width:auto;
width: auto;
}
mat-button-base {
width:auto;
width: auto;
}
::ng-deep .mat-card-image {
height:75% !important;
height: 75% !important;
}
}
}
@media (min-width: 660px) {
.col-xl-2 {
@ -109,35 +112,35 @@
min-width: 50%;
}
.col{
.col {
padding-right: 15px !important;
padding-left: 15px !important;
}
.small-padding{
.small-padding {
padding-left: 20px !important;
padding-right: 20px !important;
height:auto;
height: auto;
}
.row{
margin-left:0px;
.row {
margin-left: 0px;
}
.small-middle-container{
width:auto;
overflow:hidden;
.small-middle-container {
width: auto;
overflow: hidden;
}
.btn-group {
width:auto;
width: auto;
}
mat-button-base {
width:auto;
width: auto;
}
}
@media (min-width: 870px) {
.col-xl-2 {
flex: 0 0 33.33333%;
@ -145,7 +148,7 @@
min-width: 33.33333%;
}
}
@media (min-width: 1100px) {
.col-xl-2 {
flex: 0 0 20%;
@ -153,27 +156,29 @@
min-width: 25%;
}
}
@media (min-width: 1300px) {
@media (min-width: 1300px) {
.col-xl-2 {
flex: 0 0 18%;
max-width: 20%;
min-width: 20%;
}
}
}
@media (min-width: 1600px) {
.col-xl-2 {
flex: 0 0 16.66666667%;
max-width: 16.66666667%;
min-width: 16.66666667%;
}
}
}
@media (min-width: 1900px) {
.col-xl-2 {
flex: 0 0 14.285713%;
max-width: 14.285713%;
min-width: 14.285713%;
}
}
}
@media (min-width: 2200px) {
@ -181,7 +186,7 @@
flex: 0 0 12.5%;
max-width: 12.5%;
min-width: 12.5%;
}
}
}
@media (min-width: 2500px) {
@ -189,5 +194,5 @@
flex: 0 0 11.111111%;
max-width: 11.111111%;
min-width: 11.111111%;
}
}
}

@ -1,9 +1,10 @@
import { Component, OnInit } from "@angular/core";
import { Component, OnInit, Inject } from "@angular/core";
import { SearchV2Service } from "../../../services";
import { ISearchMovieResult, ISearchTvResult, RequestType } from "../../../interfaces";
import { IDiscoverCardResult, DiscoverOption } from "../../interfaces";
import { trigger, transition, style, animate } from "@angular/animations";
import { StorageService } from "../../../shared/storage/storage-service";
import { DOCUMENT } from "@angular/common";
@Component({
templateUrl: "./discover.component.html",
@ -42,7 +43,9 @@ export class DiscoverComponent implements OnInit {
private mediaTypeStorageKey = "DiscoverOptions";
constructor(private searchService: SearchV2Service,
private storageService: StorageService) { }
private storageService: StorageService,
@Inject(DOCUMENT) private container: Document) { }
public async ngOnInit() {
this.loading()
@ -68,6 +71,9 @@ export class DiscoverComponent implements OnInit {
this.createInitialModel();
this.scrollDisabled = false;
if (!this.containerHasScrollBar()) {
await this.onScroll();
}
}
public async onScroll() {
@ -209,7 +215,7 @@ export class DiscoverComponent implements OnInit {
public async switchDiscoverMode(newMode: DiscoverOption) {
this.loading();
this.clear();
this.discoverOptions = newMode;
this.discoverOptions = newMode;
this.storageService.save(this.mediaTypeStorageKey, newMode.toString());
await this.ngOnInit();
this.finishLoading();
@ -242,7 +248,7 @@ export class DiscoverComponent implements OnInit {
this.movies.forEach(m => {
tempResults.push({
available: m.available,
posterPath: m.posterPath ? `https://image.tmdb.org/t/p/w300/${m.posterPath}` : "../../../images/default_movie_poster.png",
posterPath: m.posterPath ? `https://image.tmdb.org/t/p/w500/${m.posterPath}` : "../../../images/default_movie_poster.png",
requested: m.requested,
title: m.title,
type: RequestType.movie,
@ -301,4 +307,11 @@ export class DiscoverComponent implements OnInit {
private finishLoading() {
this.loadingFlag = false;
}
private containerHasScrollBar(): boolean {
return
// div.scrollHeight > div.clientHeight;
this.container.documentElement.scrollHeight > this.container.documentElement.clientHeight;
// this.container.documentElement.scrollHeight > (window.innerHeight + window.pageYOffset);
}
}

@ -85,6 +85,7 @@ export interface ISonarrSettings extends IExternalSettings {
addOnly: boolean;
v3: boolean;
languageProfile: number;
scanForAvailability: boolean;
}
export interface IRadarrSettings extends IExternalSettings {
@ -95,6 +96,7 @@ export interface IRadarrSettings extends IExternalSettings {
fullRootPath: string;
addOnly: boolean;
minimumAvailability: string;
scanForAvailability: boolean;
}
export interface ILidarrSettings extends IExternalSettings {

@ -1,11 +1,4 @@
.grow-social {
transition: all .2s ease-in-out;
}
.grow-social:hover {
transform: scale(1.1);
color: black;
}
.media-icons.plex {
color: #feb801 !important;

@ -35,7 +35,7 @@
<mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
</button>
<div class="col-md-10 offset-md-1 col-10">
<div class="col-md-10 offset-md-1 col-8">
<span class="middle justify-content-center align-items-center">
<!-- Search Bar -->
<div style="width: 50%;">

@ -1,6 +1,8 @@
@import "~styles/variables.scss";
.sidenav-container {
min-height: 100vh;
-webkit-overflow-scrolling:touch;
overflow:auto;
}
.sidenav {

@ -3,6 +3,7 @@ import { AuthService } from '../auth/auth.service';
import { HubConnection } from '@aspnet/signalr';
import * as signalR from '@aspnet/signalr';
@Injectable()
export class SignalRNotificationService {
@ -28,12 +29,16 @@ export class SignalRNotificationService {
this.Notification.emit(data);
});
let retryCount = 0;
this.hubConnection.start().then((data: any) => {
console.log('Now connected');
}).catch((error: any) => {
retryCount++;
console.log('Could not connect ' + error);
setTimeout(() => this.initialize(), 3000);
if (retryCount <= 3) {
setTimeout(() => this.initialize(), 3000);
}
});
}

@ -45,7 +45,7 @@
<div class="md-form-field">
<mat-form-field *ngIf="settings.enableCustomDonations" appearance="outline" floatLabel=always>
<mat-label>Custom Donation URL</mat-label>
<input matInput placeholder="Custom Donation URL" [(ngModel)]="settings.enableCustomDonations" matTooltip="Set a custom message to be displayed in the navigation bar.">
<input matInput placeholder="Custom Donation URL" [(ngModel)]="settings.customDonationMessage" matTooltip="Set a custom message to be displayed in the navigation bar.">
</mat-form-field>
</div>
<div class="md-form-field">

@ -12,6 +12,9 @@
<div class="md-form-field">
<mat-slide-toggle [(ngModel)]="advanced" [ngModelOptions]="{standalone: true}">Advanced</mat-slide-toggle>
</div>
<div class="md-form-field">
<mat-slide-toggle formControlName="scanForAvailability">Scan for Availability</mat-slide-toggle>
</div>
</div>
</div>
</div>

@ -43,6 +43,7 @@ export class RadarrComponent implements OnInit {
port: [x.port, [Validators.required]],
addOnly: [x.addOnly],
minimumAvailability: [x.minimumAvailability, [Validators.required]],
scanForAvailability: [x.scanForAvailability]
});
if (x.defaultQualityProfile) {

@ -17,6 +17,9 @@
<div class="md-form-field">
<mat-slide-toggle [(ngModel)]="advanced" [ngModelOptions]="{standalone: true}">Advanced</mat-slide-toggle>
</div>
<div class="md-form-field">
<mat-slide-toggle formControlName="scanForAvailability">Scan for Availability</mat-slide-toggle>
</div>
</div>
</div>
</div>

@ -73,6 +73,7 @@ export class SonarrComponent implements OnInit {
seasonFolders: [x.seasonFolders],
v3: [x.v3],
languageProfile: [x.languageProfile],
scanForAvailability: [x.scanForAvailability]
});
if (x.qualityProfile) {

@ -6,14 +6,37 @@
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="showAdultMovies" name="showAdultMovies" [(ngModel)]="settings.showAdultMovies">
<label for="showAdultMovies" tooltipPosition="top" pTooltip="Include adult movies (pornography) in results">Show Adult Movies</label>
<label for="showAdultMovies" matTooltip="Include adult movies (pornography) in results">Show Adult Movies</label>
</div>
</div>
<div class="form-group">
<label class="control-label" pTooltip="Prevent movies with certain keywords from being suggested. May require a restart to take effect.">
<label class="control-label" matTooltip="Prevent movies with certain keywords from being suggested. May require a restart to take effect.">
Excluded Keyword IDs for Movie Suggestions
</label>
<form [formGroup]='tagForm'>
<mat-form-field class="example-chip-list">
<mat-chip-list #chipList>
<mat-chip *ngFor="let fruit of excludedKeywords" [selectable]="false"
[removable]="true" (removed)="remove(fruit)">
{{fruit.name}}
<mat-icon matChipRemove >cancel</mat-icon>
</mat-chip>
<input placeholder="New Keyword"
#fruitInput
formControlName='input'
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="true"
>
</mat-chip-list>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
<mat-option *ngFor="let fruit of filteredTags" [value]="fruit">
{{fruit.name}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
<!-- <tag-input #input
[(ngModel)]="excludedKeywords"
[identifyBy]="'id'" [displayBy]="'name'"

@ -8,4 +8,8 @@
::ng-deep .dark .btn:hover {
box-shadow: 0 5px 11px 0 rgba(255, 255, 255, 0.18), 0 4px 15px 0 rgba(255, 255, 255, 0.15);
color: inherit;
}
}
.example-chip-list {
width: 100%;
}

@ -1,10 +1,15 @@
import { Component, OnInit } from "@angular/core";
import { empty, of } from "rxjs";
import {COMMA, ENTER} from "@angular/cdk/keycodes";
import { Component, OnInit, ElementRef, ViewChild } from "@angular/core";
import { MatChipInputEvent } from "@angular/material/chips";
import { MatAutocompleteSelectedEvent, MatAutocomplete } from "@angular/material/autocomplete";
import { empty, of, Observable } from "rxjs";
import { ITheMovieDbSettings } from "../../interfaces";
import { ITheMovieDbSettings, IMovieDbKeyword } from "../../interfaces";
import { NotificationService } from "../../services";
import { SettingsService } from "../../services";
import { TheMovieDbService } from "../../services";
import { FormControl, FormBuilder, FormGroup } from "@angular/forms";
import { startWith, map, debounceTime, tap, switchMap, finalize } from "rxjs/operators";
interface IKeywordTag {
id: number;
@ -20,12 +25,22 @@ export class TheMovieDbComponent implements OnInit {
public settings: ITheMovieDbSettings;
public excludedKeywords: IKeywordTag[];
public tagForm: FormGroup;
public filteredTags: IMovieDbKeyword[];
@ViewChild('fruitInput') public fruitInput: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete: MatAutocomplete;
private readonly separatorKeysCodes: number[] = [ENTER, COMMA];
constructor(private settingsService: SettingsService,
private notificationService: NotificationService,
private tmdbService: TheMovieDbService) { }
private tmdbService: TheMovieDbService,
private fb: FormBuilder) { }
public ngOnInit() {
this.tagForm = this.fb.group({
input: null,
});
this.settingsService.getTheMovieDbSettings().subscribe(settings => {
this.settings = settings;
this.excludedKeywords = settings.excludedKeywordIds
@ -36,8 +51,36 @@ export class TheMovieDbComponent implements OnInit {
}))
: [];
});
this.tagForm
.get("input")
.valueChanges.pipe(
debounceTime(600),
switchMap((value: string) => {
if (value) {
return this.tmdbService.getKeywords(value);
}
})
)
.subscribe((r) => (this.filteredTags = r));
// this.tagForm.controls.input.valueChanges
// .pipe(
// debounceTime(500),
// switchMap(value => this.tmdbService.getKeywords(value))
// )
// .subscribe((data: IMovieDbKeyword[]) => {
// this.filteredTags = data;
// });
}
public async selected(event: MatAutocompleteSelectedEvent) {
const keywordId = await this.tmdbService.getKeyword(+event.option.value).toPromise();
this.excludedKeywords.push({ id: keywordId.id, name: keywordId.name, initial: false});
this.fruitInput.nativeElement.value = '';
this.tagForm.controls.input.setValue(null);
}
public autocompleteKeyword = (text: string) => this.tmdbService.getKeywords(text);
public onAddingKeyword = (tag: string | IKeywordTag) => {
@ -59,6 +102,31 @@ export class TheMovieDbComponent implements OnInit {
}
}
public async add(event: MatChipInputEvent) {
const input = event.input;
const value = event.value;
// Add our fruit
if ((value || '').trim()) {
const keyword = await this.tmdbService.getKeywords(value).toPromise();
this.excludedKeywords.push({ id: keyword[0].id, name: keyword[0].name, initial: false });
}
// Reset the input value
if (input) {
input.value = '';
}
this.tagForm.controls.input.setValue(null);
}
public remove(tag: IKeywordTag): void {
const index = this.excludedKeywords.indexOf(tag);
if (index >= 0) {
this.excludedKeywords.splice(index, 1);
}
}
public save() {
this.settings.excludedKeywordIds = this.excludedKeywords.map(k => k.id);
this.settingsService.saveTheMovieDbSettings(this.settings).subscribe(x => {

@ -20,6 +20,7 @@
.top-space {
padding-top: 2%;
}
.modal-panel {
max-height: 100vh !important;
max-width: 100vw !important;
@ -37,11 +38,19 @@
html,
body {
min-height: 100vh;
overflow: auto;
overflow: hidden;
scrollbar-color: #616161 #303030; //firefox
scrollbar-width: thin; //firefox
-webkit-overflow-scrolling: touch;
}
#main-container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: auto;
}
.spinner-container {
position: relative;
margin-left: 50%;
@ -54,7 +63,7 @@ body {
/* Scrollbar */
::-webkit-scrollbar{
::-webkit-scrollbar {
width: 7px;
background: #818181;
}
@ -64,7 +73,7 @@ body {
}
// Changed color of the scrollbar
::-webkit-scrollbar-thumb{
::-webkit-scrollbar-thumb {
border-radius: 3px;
background: #303030;
}
@ -73,13 +82,15 @@ body {
display: none;
}
.grow {
transition: all .2s ease-in-out;
}
@media (min-width: 1025px) {
.grow {
transition: all .2s ease-in-out;
}
.grow:hover {
transform: scale(1.1);
color: black;
.grow:hover {
transform: scale(1.1);
color: black;
}
}
table {
@ -91,47 +102,47 @@ table {
padding-bottom: 4%;
}
::ng-deep .dark .form-control{
background-color: rgba(0, 0, 0, 0.18);
color:#fff;
border: 1px solid rgba(0, 0, 0, 0.18);
::ng-deep .dark .form-control {
background-color: rgba(0, 0, 0, 0.18);
color: #fff;
border: 1px solid rgba(0, 0, 0, 0.18);
}
::ng-deep .dark .nav-link.active{
color: #303030;
background-color: $accent-dark;
border-color: rgba(0, 0, 0, 0.18);
font-weight:400;
::ng-deep .dark .nav-link.active {
color: #303030;
background-color: $accent-dark;
border-color: rgba(0, 0, 0, 0.18);
font-weight: 400;
}
::ng-deep .dark .nav-link{
color: #fff;
background-color: rgba(0, 0, 0, 0.18);
border-color: rgba(0, 0, 0, 0.18);
::ng-deep .dark .nav-link {
color: #fff;
background-color: rgba(0, 0, 0, 0.18);
border-color: rgba(0, 0, 0, 0.18);
}
::ng-deep .dark .ui-autocomplete.ui-autocomplete-multiple .ui-autocomplete-multiple-container .ui-autocomplete-input-token input{
color:#fff;
::ng-deep .dark .ui-autocomplete.ui-autocomplete-multiple .ui-autocomplete-multiple-container .ui-autocomplete-input-token input {
color: #fff;
}
::ng-deep .dark .ui-inputtext{
::ng-deep .dark .ui-inputtext {
background-color: rgba(0, 0, 0, 0.18);
color:#fff;
border: 1px solid rgba(0, 0, 0, 0.18);
color: #fff;
border: 1px solid rgba(0, 0, 0, 0.18);
}
::ng-deep .mat-toolbar.mat-primary{
::ng-deep .mat-toolbar.mat-primary {
margin-bottom: 0.5em;
}
::ng-deep .dark .mat-form-field.mat-focused .mat-form-field-label{
::ng-deep .dark .mat-form-field.mat-focused .mat-form-field-label {
color: $accent-dark;
}
::ng-deep .mat-form-field.mat-focused .mat-form-field-label{
::ng-deep .mat-form-field.mat-focused .mat-form-field-label {
color: $accent;
}
::ng-deep .mat-form-field-appearance-outline .mat-form-field-wrapper{
margin:0.5em;
}
::ng-deep .mat-form-field-appearance-outline .mat-form-field-wrapper {
margin: 0.5em;
}

@ -120,7 +120,10 @@ namespace Ombi.Extensions
public static void ConfigureMySql(DbContextOptionsBuilder options, PerDatabaseConfiguration config)
{
options.UseMySql(config.ConnectionString);
options.UseMySql(config.ConnectionString, b =>
{
b.CharSetBehavior(Pomelo.EntityFrameworkCore.MySql.Infrastructure.CharSetBehavior.NeverAppend);
});
}
public class DatabaseConfiguration

Loading…
Cancel
Save