mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-16 02:02:55 -07:00
commit
bb4ea79215
58 changed files with 2751 additions and 465 deletions
63
CHANGELOG.md
63
CHANGELOG.md
|
@ -1,5 +1,62 @@
|
|||
# Changelog
|
||||
|
||||
## (unreleased)
|
||||
|
||||
### **New Features**
|
||||
|
||||
- Added the ability to send newsletter out to users that are not in Ombi. [Jamie]
|
||||
|
||||
- Added the ability to turn off TV or Movies from the newsletter. [Jamie]
|
||||
|
||||
- Update about.component.html. [Jamie]
|
||||
|
||||
- Update about.component.html. [Jamie]
|
||||
|
||||
- Added random versioning prefix to the translations so the users don't have to clear the cache. [Jamie]
|
||||
|
||||
- Added more information to the about page. [Jamie]
|
||||
|
||||
- Changed let to const to adhere to linting. [Anojh]
|
||||
|
||||
- Update _Layout.cshtml. [goldenpipes]
|
||||
|
||||
- Update _Layout.cshtml. [goldenpipes]
|
||||
|
||||
- Changed the TV Request API. We now only require the TvDbId and the seasons and episodes that you want to request. This should make integration regarding TV a lot easier. [Jamie]
|
||||
|
||||
### **Fixes**
|
||||
|
||||
- Emby improvments on the way we sync/cache the data. [Jamie]
|
||||
|
||||
- Memory improvements. [Jamie]
|
||||
|
||||
- Made some improvements to the Sonarr Sync job #2127. [Jamie]
|
||||
|
||||
- Turn off Server GC to hopefully help with #2127. [Jamie Rees]
|
||||
|
||||
- Fixed #2109. [Jamie]
|
||||
|
||||
- Fixed #2101. [Jamie]
|
||||
|
||||
- Fixed #2105. [Jamie]
|
||||
|
||||
- Fixed some styling on the issues detail page. [Jamie]
|
||||
|
||||
- Fixed #2116. [Jamie]
|
||||
|
||||
- Limit the amount of FileSystemWatchers being spawned. [Jamie]
|
||||
|
||||
- Fixed the issue where Emby connect users could not log in #2115. [Jamie]
|
||||
|
||||
- Had to update some base styles since currently some styling does not look right... [Anojh]
|
||||
|
||||
- Adding wrappers and classes for LC and toggling active style for UI elements. [Anojh]
|
||||
|
||||
- Fixed a little bug in the newsletter. [Jamie]
|
||||
|
||||
- Fixed the issue where movies were not appearing in the newsletter for users with Emby #2111. [Jamie]
|
||||
|
||||
|
||||
## v3.0.3111 (2018-03-27)
|
||||
|
||||
### **New Features**
|
||||
|
@ -732,7 +789,7 @@
|
|||
|
||||
- Switch to use a single HTTPClient rather than a new one every request !dev. [tidusjar]
|
||||
|
||||
- Fix non-admin rights (#1820) [Rob Gökemeijer]
|
||||
- Fix non-admin rights (#1820) [Rob Gökemeijer]
|
||||
|
||||
- Fix duplicated "Requests" element ID on new Issues link (#1817) [Shoghi Cervantes]
|
||||
|
||||
|
@ -2582,7 +2639,7 @@
|
|||
|
||||
- WIP hide tv request options based on admin settings. [Matt McHughes]
|
||||
|
||||
- Set meta charset to be utf-8. [Madeleine Schönemann]
|
||||
- Set meta charset to be utf-8. [Madeleine Schönemann]
|
||||
|
||||
- F#552: updated labels text. [Jim MacKenize]
|
||||
|
||||
|
@ -2939,7 +2996,7 @@
|
|||
|
||||
- Fixed issues from the merge. [tidusjar]
|
||||
|
||||
- Stupid &$(*£ merge. [tidusjar]
|
||||
- Stupid &$(*£ merge. [tidusjar]
|
||||
|
||||
- Angular. [tidusjar]
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ version: 3.0.{build}
|
|||
configuration: Release
|
||||
os: Visual Studio 2017
|
||||
environment:
|
||||
nodejs_version: "7.8.0"
|
||||
nodejs_version: "Current"
|
||||
|
||||
install:
|
||||
# Get the latest stable version of Node.js or io.js
|
||||
|
|
|
@ -77,13 +77,19 @@ namespace Ombi.Api.Emby
|
|||
|
||||
request.AddJsonBody(body);
|
||||
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddContentHeader("Content-Type", "application/json");
|
||||
AddEmbyHeaders(request);
|
||||
|
||||
var obj = await Api.Request<EmbyConnectUser>(request);
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static void AddEmbyHeaders(Request request)
|
||||
{
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("X-Application", $"Ombi/{AssemblyHelper.GetRuntimeVersion()}");
|
||||
request.AddContentHeader("Content-Type", "application/json");
|
||||
}
|
||||
|
||||
public async Task<EmbyItemContainer<MovieInformation>> GetCollection(string mediaId, string apiKey, string userId, string baseUrl)
|
||||
{
|
||||
var request = new Request($"emby/users/{userId}/items?parentId={mediaId}", baseUrl, HttpMethod.Get);
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
[Test]
|
||||
public async Task Movie_ShouldBe_Available_WhenFoundInEmby()
|
||||
{
|
||||
ContextMock.Setup(x => x.Get(It.IsAny<string>())).ReturnsAsync(new EmbyContent
|
||||
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
|
||||
{
|
||||
ProviderId = "123"
|
||||
});
|
||||
|
@ -39,7 +39,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
[Test]
|
||||
public async Task Movie_ShouldBe_NotAvailable_WhenNotFoundInEmby()
|
||||
{
|
||||
ContextMock.Setup(x => x.Get(It.IsAny<string>())).Returns(Task.FromResult(default(EmbyContent)));
|
||||
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).Returns(Task.FromResult(default(EmbyContent)));
|
||||
var search = new SearchMovieViewModel();
|
||||
var result = await Rule.Execute(search);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
|
||||
|
@ -9,7 +10,7 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
{
|
||||
|
||||
Task RemoveTvRequest(int requestId);
|
||||
Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv);
|
||||
Task<RequestEngineResult> RequestTvShow(TvRequestViewModel tv);
|
||||
Task<RequestEngineResult> DenyChildRequest(int requestId);
|
||||
Task<IEnumerable<TvRequests>> SearchTvRequest(string search);
|
||||
Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvRequestTree(string search);
|
||||
|
|
|
@ -152,7 +152,9 @@ namespace Ombi.Core.Engine
|
|||
model.Add(new RecentlyAddedMovieModel
|
||||
{
|
||||
Id = emby.Id,
|
||||
ImdbId = emby.ProviderId,
|
||||
ImdbId = emby.ImdbId,
|
||||
TheMovieDbId = emby.TheMovieDbId,
|
||||
TvDbId = emby.TvDbId,
|
||||
AddedAt = emby.AddedAt,
|
||||
Title = emby.Title,
|
||||
});
|
||||
|
@ -211,7 +213,9 @@ namespace Ombi.Core.Engine
|
|||
model.Add(new RecentlyAddedTvModel
|
||||
{
|
||||
Id = emby.Id,
|
||||
ImdbId = emby.ProviderId,
|
||||
ImdbId = emby.ImdbId,
|
||||
TvDbId = emby.TvDbId,
|
||||
TheMovieDbId = emby.TheMovieDbId,
|
||||
AddedAt = emby.AddedAt,
|
||||
Title = emby.Title,
|
||||
EpisodeNumber = episode.EpisodeNumber,
|
||||
|
|
|
@ -43,13 +43,13 @@ namespace Ombi.Core.Engine
|
|||
private IAuditRepository Audit { get; }
|
||||
private readonly IRepository<RequestLog> _requestLog;
|
||||
|
||||
public async Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv)
|
||||
public async Task<RequestEngineResult> RequestTvShow(TvRequestViewModel tv)
|
||||
{
|
||||
var user = await GetUser();
|
||||
|
||||
var tvBuilder = new TvShowRequestBuilder(TvApi);
|
||||
(await tvBuilder
|
||||
.GetShowInfo(tv.Id))
|
||||
.GetShowInfo(tv.TvDbId))
|
||||
.CreateTvList(tv)
|
||||
.CreateChild(tv, user.Id);
|
||||
|
||||
|
@ -78,9 +78,9 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
}
|
||||
|
||||
await Audit.Record(AuditType.Added, AuditArea.TvRequest, $"Added Request {tv.Title}", Username);
|
||||
await Audit.Record(AuditType.Added, AuditArea.TvRequest, $"Added Request {tvBuilder.ChildRequest.Title}", Username);
|
||||
|
||||
var existingRequest = await TvRepository.Get().FirstOrDefaultAsync(x => x.TvDbId == tv.Id);
|
||||
var existingRequest = await TvRepository.Get().FirstOrDefaultAsync(x => x.TvDbId == tv.TvDbId);
|
||||
if (existingRequest != null)
|
||||
{
|
||||
// Remove requests we already have, we just want new ones
|
||||
|
@ -127,7 +127,7 @@ namespace Ombi.Core.Engine
|
|||
var newRequest = tvBuilder.CreateNewRequest(tv);
|
||||
return await AddRequest(newRequest.NewRequest);
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<TvRequests>> GetRequests(int count, int position)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Ombi.Api.TvMaze;
|
||||
using Ombi.Api.TvMaze.Models;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
|
@ -23,7 +24,7 @@ namespace Ombi.Core.Helpers
|
|||
private ITvMazeApi TvApi { get; }
|
||||
|
||||
public ChildRequests ChildRequest { get; set; }
|
||||
public List<SeasonRequests> TvRequests { get; protected set; }
|
||||
public List<SeasonsViewModel> TvRequests { get; protected set; }
|
||||
public string PosterPath { get; protected set; }
|
||||
public DateTime FirstAir { get; protected set; }
|
||||
public TvRequests NewRequest { get; protected set; }
|
||||
|
@ -33,7 +34,7 @@ namespace Ombi.Core.Helpers
|
|||
{
|
||||
ShowInfo = await TvApi.ShowLookupByTheTvDbId(id);
|
||||
|
||||
DateTime.TryParse(ShowInfo.premiered, out DateTime dt);
|
||||
DateTime.TryParse(ShowInfo.premiered, out var dt);
|
||||
|
||||
FirstAir = dt;
|
||||
|
||||
|
@ -43,37 +44,29 @@ namespace Ombi.Core.Helpers
|
|||
return this;
|
||||
}
|
||||
|
||||
public TvShowRequestBuilder CreateChild(SearchTvShowViewModel model, string userId)
|
||||
public TvShowRequestBuilder CreateChild(TvRequestViewModel model, string userId)
|
||||
{
|
||||
ChildRequest = new ChildRequests
|
||||
{
|
||||
Id = model.Id,
|
||||
Id = model.TvDbId,
|
||||
RequestType = RequestType.TvShow,
|
||||
RequestedDate = DateTime.UtcNow,
|
||||
Approved = false,
|
||||
RequestedUserId = userId,
|
||||
SeasonRequests = new List<SeasonRequests>(),
|
||||
Title = model.Title,
|
||||
Title = ShowInfo.name,
|
||||
SeriesType = ShowInfo.type.Equals("Animation", StringComparison.CurrentCultureIgnoreCase) ? SeriesType.Anime : SeriesType.Standard
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public TvShowRequestBuilder CreateTvList(SearchTvShowViewModel tv)
|
||||
public TvShowRequestBuilder CreateTvList(TvRequestViewModel tv)
|
||||
{
|
||||
TvRequests = new List<SeasonRequests>();
|
||||
TvRequests = new List<SeasonsViewModel>();
|
||||
// Only have the TV requests we actually requested and not everything
|
||||
foreach (var season in tv.SeasonRequests)
|
||||
foreach (var season in tv.Seasons)
|
||||
{
|
||||
for (int i = season.Episodes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (!season.Episodes[i].Requested)
|
||||
{
|
||||
season.Episodes.RemoveAt(i); // Remove the episode since it's not requested
|
||||
}
|
||||
}
|
||||
|
||||
if (season.Episodes.Any())
|
||||
{
|
||||
TvRequests.Add(season);
|
||||
|
@ -81,11 +74,10 @@ namespace Ombi.Core.Helpers
|
|||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<TvShowRequestBuilder> BuildEpisodes(SearchTvShowViewModel tv)
|
||||
public async Task<TvShowRequestBuilder> BuildEpisodes(TvRequestViewModel tv)
|
||||
{
|
||||
if (tv.RequestAll)
|
||||
{
|
||||
|
@ -173,26 +165,68 @@ namespace Ombi.Core.Helpers
|
|||
else
|
||||
{
|
||||
// It's a custom request
|
||||
ChildRequest.SeasonRequests = TvRequests;
|
||||
var seasonRequests = new List<SeasonRequests>();
|
||||
var episodes = await TvApi.EpisodeLookup(ShowInfo.id);
|
||||
foreach (var ep in episodes)
|
||||
{
|
||||
var existingSeasonRequest = seasonRequests.FirstOrDefault(x => x.SeasonNumber == ep.season);
|
||||
if (existingSeasonRequest != null)
|
||||
{
|
||||
var requestedSeason = tv.Seasons.FirstOrDefault(x => x.SeasonNumber == ep.season);
|
||||
var requestedEpisode = requestedSeason?.Episodes?.Any(x => x.EpisodeNumber == ep.number) ?? false;
|
||||
if (requestedSeason != null && requestedEpisode)
|
||||
{
|
||||
// We already have this, let's just add the episodes to it
|
||||
existingSeasonRequest.Episodes.Add(new EpisodeRequests
|
||||
{
|
||||
EpisodeNumber = ep.number,
|
||||
AirDate = FormatDate(ep.airdate),
|
||||
Title = ep.name,
|
||||
Url = ep.url,
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var newRequest = new SeasonRequests {SeasonNumber = ep.season};
|
||||
var requestedSeason = tv.Seasons.FirstOrDefault(x => x.SeasonNumber == ep.season);
|
||||
var requestedEpisode = requestedSeason?.Episodes?.Any(x => x.EpisodeNumber == ep.number) ?? false;
|
||||
if (requestedSeason != null && requestedEpisode)
|
||||
{
|
||||
newRequest.Episodes.Add(new EpisodeRequests
|
||||
{
|
||||
EpisodeNumber = ep.number,
|
||||
AirDate = FormatDate(ep.airdate),
|
||||
Title = ep.name,
|
||||
Url = ep.url,
|
||||
});
|
||||
seasonRequests.Add(newRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var s in seasonRequests)
|
||||
{
|
||||
ChildRequest.SeasonRequests.Add(s);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public TvShowRequestBuilder CreateNewRequest(SearchTvShowViewModel tv)
|
||||
public TvShowRequestBuilder CreateNewRequest(TvRequestViewModel tv)
|
||||
{
|
||||
NewRequest = new TvRequests
|
||||
{
|
||||
Id = tv.Id,
|
||||
Overview = ShowInfo.summary.RemoveHtml(),
|
||||
PosterPath = PosterPath,
|
||||
Title = ShowInfo.name,
|
||||
ReleaseDate = FirstAir,
|
||||
Status = ShowInfo.status,
|
||||
ImdbId = ShowInfo.externals?.imdb ?? string.Empty,
|
||||
TvDbId = tv.Id,
|
||||
TvDbId = tv.TvDbId,
|
||||
ChildRequests = new List<ChildRequests>(),
|
||||
TotalSeasons = tv.SeasonRequests.Count()
|
||||
TotalSeasons = tv.Seasons.Count()
|
||||
};
|
||||
NewRequest.ChildRequests.Add(ChildRequest);
|
||||
|
||||
|
|
25
src/Ombi.Core/Models/Requests/TvRequestViewModel.cs
Normal file
25
src/Ombi.Core/Models/Requests/TvRequestViewModel.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Core.Models.Requests
|
||||
{
|
||||
public class TvRequestViewModel
|
||||
{
|
||||
public bool RequestAll { get; set; }
|
||||
public bool LatestSeason { get; set; }
|
||||
public bool FirstSeason { get; set; }
|
||||
public int TvDbId { get; set; }
|
||||
public List<SeasonsViewModel> Seasons { get; set; } = new List<SeasonsViewModel>();
|
||||
}
|
||||
|
||||
public class SeasonsViewModel
|
||||
{
|
||||
public int SeasonNumber { get; set; }
|
||||
public List<EpisodesViewModel> Episodes { get; set; } = new List<EpisodesViewModel>();
|
||||
}
|
||||
|
||||
public class EpisodesViewModel
|
||||
{
|
||||
public int EpisodeNumber { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -23,20 +23,20 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
EmbyContent item = null;
|
||||
if (obj.ImdbId.HasValue())
|
||||
{
|
||||
item = await EmbyContentRepository.Get(obj.ImdbId);
|
||||
item = await EmbyContentRepository.GetByImdbId(obj.ImdbId);
|
||||
}
|
||||
if (item == null)
|
||||
{
|
||||
if (obj.TheMovieDbId.HasValue())
|
||||
{
|
||||
item = await EmbyContentRepository.Get(obj.TheMovieDbId);
|
||||
item = await EmbyContentRepository.GetByTheMovieDbId(obj.TheMovieDbId);
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
if (obj.TheTvDbId.HasValue())
|
||||
{
|
||||
item = await EmbyContentRepository.Get(obj.TheTvDbId);
|
||||
item = await EmbyContentRepository.GetByTvDbId(obj.TheTvDbId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,11 +29,19 @@ namespace Ombi.Notifications
|
|||
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
|
||||
RequestedUser = req?.RequestedUser?.UserName;
|
||||
UserName = req?.RequestedUser?.UserName;
|
||||
if (UserName.IsNullOrEmpty())
|
||||
{
|
||||
// Can be set if it's an issue
|
||||
UserName = req?.RequestedUser?.UserName;
|
||||
}
|
||||
|
||||
Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName;
|
||||
Title = title;
|
||||
RequestedDate = req?.RequestedDate.ToString("D");
|
||||
Type = req?.RequestType.ToString();
|
||||
if (Type.IsNullOrEmpty())
|
||||
{
|
||||
Type = req?.RequestType.ToString();
|
||||
}
|
||||
Overview = req?.Overview;
|
||||
Year = req?.ReleaseDate.Year.ToString();
|
||||
PosterImage = req?.RequestType == RequestType.Movie ?
|
||||
|
@ -65,11 +73,19 @@ namespace Ombi.Notifications
|
|||
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
|
||||
RequestedUser = req?.RequestedUser?.UserName;
|
||||
UserName = req?.RequestedUser?.UserName;
|
||||
if (UserName.IsNullOrEmpty())
|
||||
{
|
||||
// Can be set if it's an issue
|
||||
UserName = req?.RequestedUser?.UserName;
|
||||
}
|
||||
Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName;
|
||||
Title = title;
|
||||
RequestedDate = req?.RequestedDate.ToString("D");
|
||||
Type = req?.RequestType.ToString();
|
||||
if (Type.IsNullOrEmpty())
|
||||
{
|
||||
Type = req?.RequestType.ToString();
|
||||
}
|
||||
|
||||
Overview = req?.ParentRequest.Overview;
|
||||
Year = req?.ParentRequest.ReleaseDate.Year.ToString();
|
||||
PosterImage = req?.RequestType == RequestType.Movie ?
|
||||
|
@ -128,6 +144,7 @@ namespace Ombi.Notifications
|
|||
IssueSubject = opts.Substitutes.TryGetValue("IssueSubject", out val) ? val : string.Empty;
|
||||
NewIssueComment = opts.Substitutes.TryGetValue("NewIssueComment", out val) ? val : string.Empty;
|
||||
UserName = opts.Substitutes.TryGetValue("IssueUser", out val) ? val : string.Empty;
|
||||
Type = opts.Substitutes.TryGetValue("RequestType", out val) ? val : string.Empty;
|
||||
}
|
||||
|
||||
// User Defined
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Hangfire;
|
||||
using System;
|
||||
using Hangfire;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Schedule.Jobs;
|
||||
using Ombi.Schedule.Jobs.Couchpotato;
|
||||
|
@ -12,7 +13,7 @@ using Ombi.Settings.Settings.Models;
|
|||
|
||||
namespace Ombi.Schedule
|
||||
{
|
||||
public class JobSetup : IJobSetup
|
||||
public class JobSetup : IJobSetup, IDisposable
|
||||
{
|
||||
public JobSetup(IPlexContentSync plexContentSync, IRadarrSync radarrSync,
|
||||
IOmbiAutomaticUpdater updater, IEmbyContentSync embySync, IPlexUserImporter userImporter,
|
||||
|
@ -65,5 +66,36 @@ namespace Ombi.Schedule
|
|||
RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
||||
}
|
||||
|
||||
|
||||
private bool _disposed;
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_plexContentSync?.Dispose();
|
||||
_radarrSync?.Dispose();
|
||||
_updater?.Dispose();
|
||||
_plexUserImporter?.Dispose();
|
||||
_embyContentSync?.Dispose();
|
||||
_embyUserImporter?.Dispose();
|
||||
_sonarrSync?.Dispose();
|
||||
_cpCache?.Dispose();
|
||||
_srSync?.Dispose();
|
||||
_jobSettings?.Dispose();
|
||||
_refreshMetadata?.Dispose();
|
||||
_newsletter?.Dispose();
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,16 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
|
||||
foreach (var movie in movies)
|
||||
{
|
||||
var embyContent = await _repo.Get(movie.ImdbId);
|
||||
EmbyContent embyContent = null;
|
||||
if (movie.TheMovieDbId > 0)
|
||||
{
|
||||
embyContent = await _repo.GetByTheMovieDbId(movie.TheMovieDbId.ToString());
|
||||
}
|
||||
else if(movie.ImdbId.HasValue())
|
||||
{
|
||||
embyContent = await _repo.GetByImdbId(movie.ImdbId);
|
||||
}
|
||||
|
||||
if (embyContent == null)
|
||||
{
|
||||
// We don't have this yet
|
||||
|
@ -112,8 +121,20 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
|
||||
foreach (var child in tv)
|
||||
{
|
||||
var tvDbId = child.ParentRequest.TvDbId;
|
||||
var seriesEpisodes = embyEpisodes.Where(x => x.Series.ProviderId == tvDbId.ToString());
|
||||
IQueryable<EmbyEpisode> seriesEpisodes;
|
||||
if (child.ParentRequest.TvDbId > 0)
|
||||
{
|
||||
seriesEpisodes = embyEpisodes.Where(x => x.Series.TvDbId == child.ParentRequest.TvDbId.ToString());
|
||||
}
|
||||
else if(child.ParentRequest.ImdbId.HasValue())
|
||||
{
|
||||
seriesEpisodes = embyEpisodes.Where(x => x.Series.ImdbId == child.ParentRequest.ImdbId);
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var season in child.SeasonRequests)
|
||||
{
|
||||
foreach (var episode in season.Episodes)
|
||||
|
|
|
@ -38,12 +38,21 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
|
||||
public async Task Start()
|
||||
{
|
||||
var embySettings = await _settings.GetSettingsAsync();
|
||||
var embySettings = await _settings.GetSettingsAsync();
|
||||
if (!embySettings.Enable)
|
||||
return;
|
||||
|
||||
foreach (var server in embySettings.Servers)
|
||||
await StartServerCache(server);
|
||||
{
|
||||
try
|
||||
{
|
||||
await StartServerCache(server);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Exception when caching Emby for server {0}", server.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Episodes
|
||||
BackgroundJob.Enqueue(() => _episodeSync.Start());
|
||||
|
@ -55,8 +64,11 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
if (!ValidateSettings(server))
|
||||
return;
|
||||
|
||||
await _repo.ExecuteSql("DELETE FROM EmbyEpisode");
|
||||
await _repo.ExecuteSql("DELETE FROM EmbyContent");
|
||||
|
||||
var movies = await _api.GetAllMovies(server.ApiKey, server.AdministratorId, server.FullUri);
|
||||
var mediaToAdd = new List<EmbyContent>();
|
||||
var mediaToAdd = new HashSet<EmbyContent>();
|
||||
foreach (var movie in movies.Items)
|
||||
{
|
||||
if (movie.Type.Equals("boxset", StringComparison.CurrentCultureIgnoreCase))
|
||||
|
@ -96,7 +108,9 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
if (existingTv == null)
|
||||
mediaToAdd.Add(new EmbyContent
|
||||
{
|
||||
ProviderId = tvInfo.ProviderIds.Tvdb,
|
||||
TvDbId = tvInfo.ProviderIds?.Tvdb,
|
||||
ImdbId = tvInfo.ProviderIds?.Imdb,
|
||||
TheMovieDbId = tvInfo.ProviderIds?.Tmdb,
|
||||
Title = tvInfo.Name,
|
||||
Type = EmbyMediaType.Series,
|
||||
EmbyId = tvShow.Id,
|
||||
|
@ -110,18 +124,14 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
|
||||
private async Task ProcessMovies(MovieInformation movieInfo, ICollection<EmbyContent> content)
|
||||
{
|
||||
if (string.IsNullOrEmpty(movieInfo.ProviderIds.Imdb))
|
||||
{
|
||||
Log.Error("Provider Id on movie {0} is null", movieInfo.Name);
|
||||
return;
|
||||
}
|
||||
// Check if it exists
|
||||
var existingMovie = await _repo.GetByEmbyId(movieInfo.Id);
|
||||
|
||||
if (existingMovie == null)
|
||||
content.Add(new EmbyContent
|
||||
{
|
||||
ProviderId = movieInfo.ProviderIds.Imdb,
|
||||
ImdbId = movieInfo.ProviderIds.Imdb,
|
||||
TheMovieDbId = movieInfo.ProviderIds?.Tmdb,
|
||||
Title = movieInfo.Name,
|
||||
Type = EmbyMediaType.Movie,
|
||||
EmbyId = movieInfo.Id,
|
||||
|
|
|
@ -85,10 +85,10 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
}
|
||||
|
||||
var epInfo = await _api.GetEpisodeInformation(ep.Id, server.ApiKey, server.AdministratorId, server.FullUri);
|
||||
if (epInfo?.ProviderIds?.Tvdb == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//if (epInfo?.ProviderIds?.Tvdb == null)
|
||||
//{
|
||||
// continue;
|
||||
//}
|
||||
|
||||
// Let's make sure we have the parent request, stop those pesky forign key errors,
|
||||
// Damn me having data integrity
|
||||
|
@ -109,7 +109,9 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
EpisodeNumber = ep.IndexNumber,
|
||||
SeasonNumber = ep.ParentIndexNumber,
|
||||
ParentId = ep.SeriesId,
|
||||
ProviderId = epInfo.ProviderIds.Tvdb,
|
||||
TvDbId = epInfo.ProviderIds.Tvdb,
|
||||
TheMovieDbId = epInfo.ProviderIds.Tmdb,
|
||||
ImdbId = epInfo.ProviderIds.Imdb,
|
||||
Title = ep.Name,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MailKit;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
|
@ -100,18 +101,18 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var embym = embyContent.Where(x => x.Type == EmbyMediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10);
|
||||
var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10);
|
||||
var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10);
|
||||
body = await BuildHtml(plexm, embym, plext, embyt);
|
||||
body = await BuildHtml(plexm, embym, plext, embyt, settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend);
|
||||
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, settings);
|
||||
if (body.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!test)
|
||||
{
|
||||
// Get the users to send it to
|
||||
|
@ -120,6 +121,15 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var emails in settings.ExternalEmails)
|
||||
{
|
||||
users.Add(new OmbiUser
|
||||
{
|
||||
UserName = emails,
|
||||
Email = emails
|
||||
});
|
||||
}
|
||||
var emailTasks = new List<Task>();
|
||||
foreach (var user in users)
|
||||
{
|
||||
|
@ -229,20 +239,20 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
return resolver.ParseMessage(template, curlys);
|
||||
}
|
||||
|
||||
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend, IQueryable<PlexEpisode> plexEpisodes, IQueryable<EmbyEpisode> embyEp)
|
||||
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend, IQueryable<PlexEpisode> plexEpisodes, IQueryable<EmbyEpisode> embyEp, NewsletterSettings settings)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
var plexMovies = plexContentToSend.Where(x => x.Type == PlexMediaTypeEntity.Movie);
|
||||
var embyMovies = embyContentToSend.Where(x => x.Type == EmbyMediaType.Movie);
|
||||
if (plexMovies.Any() || embyMovies.Any())
|
||||
if ((plexMovies.Any() || embyMovies.Any()) && !settings.DisableMovies)
|
||||
{
|
||||
sb.Append("<h1>New Movies:</h1><br /><br />");
|
||||
await ProcessPlexMovies(plexMovies, sb);
|
||||
await ProcessEmbyMovies(embyMovies, sb);
|
||||
}
|
||||
|
||||
if (plexEpisodes.Any() || embyEp.Any())
|
||||
if ((plexEpisodes.Any() || embyEp.Any()) && !settings.DisableTv)
|
||||
{
|
||||
sb.Append("<h1>New Episodes:</h1><br /><br />");
|
||||
await ProcessPlexTv(plexEpisodes, sb);
|
||||
|
@ -259,19 +269,11 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var ordered = plexContentToSend.OrderByDescending(x => x.AddedAt);
|
||||
foreach (var content in ordered)
|
||||
{
|
||||
if (content.TheMovieDbId.IsNullOrEmpty())
|
||||
{
|
||||
// Maybe we should try the ImdbId?
|
||||
if (content.ImdbId.HasValue())
|
||||
{
|
||||
var findResult = await _movieApi.Find(content.ImdbId, ExternalSource.imdb_id);
|
||||
|
||||
var movieId = findResult.movie_results?[0]?.id ?? 0;
|
||||
content.TheMovieDbId = movieId.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
int.TryParse(content.TheMovieDbId, out var movieDbId);
|
||||
if (movieDbId <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var info = await _movieApi.GetMovieInformationWithExtraInfo(movieDbId);
|
||||
if (info == null)
|
||||
{
|
||||
|
@ -300,8 +302,21 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var ordered = embyContent.OrderByDescending(x => x.AddedAt);
|
||||
foreach (var content in ordered)
|
||||
{
|
||||
int.TryParse(content.ProviderId, out var movieDbId);
|
||||
var info = await _movieApi.GetMovieInformationWithExtraInfo(movieDbId);
|
||||
var theMovieDbId = content.TheMovieDbId;
|
||||
if (!content.TheMovieDbId.HasValue())
|
||||
{
|
||||
var imdbId = content.ImdbId;
|
||||
var findResult = await _movieApi.Find(imdbId, ExternalSource.imdb_id);
|
||||
var result = findResult.movie_results?.FirstOrDefault();
|
||||
if (result == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
theMovieDbId = result.id.ToString();
|
||||
}
|
||||
|
||||
var info = await _movieApi.GetMovieInformationWithExtraInfo(int.Parse(theMovieDbId));
|
||||
if (info == null)
|
||||
{
|
||||
continue;
|
||||
|
@ -505,7 +520,11 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
try
|
||||
{
|
||||
int.TryParse(t.ProviderId, out var tvdbId);
|
||||
if (!t.TvDbId.HasValue())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int.TryParse(t.TvDbId, out var tvdbId);
|
||||
var info = await _tvApi.ShowLookupByTheTvDbId(tvdbId);
|
||||
if (info == null)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,6 @@ using Ombi.Core.Settings.Models.External;
|
|||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
{
|
||||
|
@ -44,6 +43,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
if (settings.Enable)
|
||||
{
|
||||
await StartPlex();
|
||||
await StartEmby();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -61,6 +61,12 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
await StartPlexTv();
|
||||
}
|
||||
|
||||
private async Task StartEmby()
|
||||
{
|
||||
await StartEmbyMovies();
|
||||
await StartEmbyTv();
|
||||
}
|
||||
|
||||
private async Task StartPlexTv()
|
||||
{
|
||||
var allTv = _plexRepo.GetAll().Where(x =>
|
||||
|
@ -101,6 +107,46 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
await _plexRepo.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task StartEmbyTv()
|
||||
{
|
||||
var allTv = _embyRepo.GetAll().Where(x =>
|
||||
x.Type == EmbyMediaType.Series && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue() || !x.TvDbId.HasValue()));
|
||||
var tvCount = 0;
|
||||
foreach (var show in allTv)
|
||||
{
|
||||
var hasImdb = show.ImdbId.HasValue();
|
||||
var hasTheMovieDb = show.TheMovieDbId.HasValue();
|
||||
var hasTvDbId = show.TvDbId.HasValue();
|
||||
|
||||
if (!hasTheMovieDb)
|
||||
{
|
||||
var id = await GetTheMovieDbId(hasTvDbId, hasImdb, show.TvDbId, show.ImdbId, show.Title);
|
||||
show.TheMovieDbId = id;
|
||||
}
|
||||
|
||||
if (!hasImdb)
|
||||
{
|
||||
var id = await GetImdbId(hasTheMovieDb, hasTvDbId, show.Title, show.TheMovieDbId, show.TvDbId);
|
||||
show.ImdbId = id;
|
||||
_embyRepo.UpdateWithoutSave(show);
|
||||
}
|
||||
|
||||
if (!hasTvDbId)
|
||||
{
|
||||
var id = await GetTvDbId(hasTheMovieDb, hasImdb, show.TheMovieDbId, show.ImdbId, show.Title);
|
||||
show.TvDbId = id;
|
||||
_embyRepo.UpdateWithoutSave(show);
|
||||
}
|
||||
tvCount++;
|
||||
if (tvCount >= 20)
|
||||
{
|
||||
await _embyRepo.SaveChangesAsync();
|
||||
tvCount = 0;
|
||||
}
|
||||
}
|
||||
await _embyRepo.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task StartPlexMovies()
|
||||
{
|
||||
var allMovies = _plexRepo.GetAll().Where(x =>
|
||||
|
@ -135,7 +181,41 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
await _plexRepo.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task<string> GetTheMovieDbId(bool hasTvDbId, bool hasImdb, string tvdbID, string imdbId, string title)
|
||||
private async Task StartEmbyMovies()
|
||||
{
|
||||
var allMovies = _embyRepo.GetAll().Where(x =>
|
||||
x.Type == EmbyMediaType.Movie && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue()));
|
||||
int movieCount = 0;
|
||||
foreach (var movie in allMovies)
|
||||
{
|
||||
var hasImdb = movie.ImdbId.HasValue();
|
||||
var hasTheMovieDb = movie.TheMovieDbId.HasValue();
|
||||
// Movies don't really use TheTvDb
|
||||
|
||||
if (!hasImdb)
|
||||
{
|
||||
var imdbId = await GetImdbId(hasTheMovieDb, false, movie.Title, movie.TheMovieDbId, string.Empty);
|
||||
movie.ImdbId = imdbId;
|
||||
_embyRepo.UpdateWithoutSave(movie);
|
||||
}
|
||||
if (!hasTheMovieDb)
|
||||
{
|
||||
var id = await GetTheMovieDbId(false, hasImdb, string.Empty, movie.ImdbId, movie.Title);
|
||||
movie.TheMovieDbId = id;
|
||||
_embyRepo.UpdateWithoutSave(movie);
|
||||
}
|
||||
movieCount++;
|
||||
if (movieCount >= 20)
|
||||
{
|
||||
await _embyRepo.SaveChangesAsync();
|
||||
movieCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
await _embyRepo.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task<string> GetTheMovieDbId(bool hasTvDbId, bool hasImdb, string tvdbID, string imdbId, string title)
|
||||
{
|
||||
_log.LogInformation("The Media item {0} does not have a TheMovieDbId, searching for TheMovieDbId", title);
|
||||
FindResult result = null;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -43,14 +45,15 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
var series = await _api.GetSeries(settings.ApiKey, settings.FullUri);
|
||||
if (series != null)
|
||||
{
|
||||
var sonarrSeries = series as IList<SonarrSeries> ?? series.ToList();
|
||||
var sonarrSeries = series as ImmutableHashSet<SonarrSeries> ?? series.ToImmutableHashSet();
|
||||
var ids = sonarrSeries.Select(x => x.tvdbId);
|
||||
|
||||
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrCache");
|
||||
var entites = ids.Select(id => new SonarrCache { TvDbId = id }).ToList();
|
||||
var entites = ids.Select(id => new SonarrCache { TvDbId = id }).ToImmutableHashSet();
|
||||
|
||||
await _ctx.SonarrCache.AddRangeAsync(entites);
|
||||
|
||||
entites.Clear();
|
||||
|
||||
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrEpisodeCache");
|
||||
foreach (var s in sonarrSeries)
|
||||
{
|
||||
|
@ -67,10 +70,10 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
TvDbId = s.tvdbId,
|
||||
HasFile = episode.hasFile
|
||||
}));
|
||||
_log.LogDebug("Commiting the transaction");
|
||||
await _ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
_log.LogDebug("Commiting the transaction");
|
||||
await _ctx.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -46,8 +46,7 @@ namespace Ombi.Schedule.Processor
|
|||
if (masterBranch)
|
||||
{
|
||||
latestRelease = doc.DocumentNode.Descendants("h2")
|
||||
.FirstOrDefault(x => x.InnerText == "(unreleased)");
|
||||
// TODO: Change this to InnterText != "(unreleased)" once we go live and it's not a prerelease
|
||||
.FirstOrDefault(x => x.InnerText != "(unreleased)");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
namespace Ombi.Settings.Settings.Models.Notifications
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Settings.Settings.Models.Notifications
|
||||
{
|
||||
public class NewsletterSettings : Settings
|
||||
{
|
||||
public bool DisableTv { get; set; }
|
||||
public bool DisableMovies { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public List<string> ExternalEmails { get; set; }
|
||||
}
|
||||
}
|
|
@ -36,11 +36,18 @@ namespace Ombi.Store.Entities
|
|||
{
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OBSOLETE, Cannot delete due to DB migration issues with SQLite
|
||||
/// </summary>
|
||||
public string ProviderId { get; set; }
|
||||
public string EmbyId { get; set; }
|
||||
public EmbyMediaType Type { get; set; }
|
||||
public DateTime AddedAt { get; set; }
|
||||
|
||||
public string ImdbId { get; set; }
|
||||
public string TheMovieDbId { get; set; }
|
||||
public string TvDbId { get; set; }
|
||||
|
||||
|
||||
public ICollection<EmbyEpisode> Episodes { get; set; }
|
||||
}
|
||||
|
|
|
@ -39,8 +39,14 @@ namespace Ombi.Store.Entities
|
|||
public int EpisodeNumber { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public string ParentId { get; set; }
|
||||
/// <summary>
|
||||
/// NOT USED
|
||||
/// </summary>
|
||||
public string ProviderId { get; set; }
|
||||
public DateTime AddedAt { get; set; }
|
||||
public string TvDbId { get; set; }
|
||||
public string ImdbId { get; set; }
|
||||
public string TheMovieDbId { get; set; }
|
||||
|
||||
public EmbyContent Series { get; set; }
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ombi.Store.Repository.Requests
|
|||
public class SeasonRequests : Entity
|
||||
{
|
||||
public int SeasonNumber { get; set; }
|
||||
public List<EpisodeRequests> Episodes { get; set; }
|
||||
public List<EpisodeRequests> Episodes { get; set; } = new List<EpisodeRequests>();
|
||||
|
||||
public int ChildRequestId { get; set; }
|
||||
[ForeignKey(nameof(ChildRequestId))]
|
||||
|
|
948
src/Ombi.Store/Migrations/20180406224743_EmbyMetadata.Designer.cs
generated
Normal file
948
src/Ombi.Store/Migrations/20180406224743_EmbyMetadata.Designer.cs
generated
Normal file
|
@ -0,0 +1,948 @@
|
|||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using System;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
[DbContext(typeof(OmbiContext))]
|
||||
[Migration("20180406224743_EmbyMetadata")]
|
||||
partial class EmbyMetadata
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ApplicationConfiguration");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Audit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AuditArea");
|
||||
|
||||
b.Property<int>("AuditType");
|
||||
|
||||
b.Property<DateTime>("DateTime");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("User");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Audit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchPotatoCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EmbyContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ParentId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentId");
|
||||
|
||||
b.ToTable("EmbyEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Content");
|
||||
|
||||
b.Property<string>("SettingsName");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("GlobalSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Agent");
|
||||
|
||||
b.Property<bool>("Enabled");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<int>("NotificationType");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("NotificationTemplates");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("PlayerId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("NotificationUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("Alias");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<string>("EmbyConnectUserId");
|
||||
|
||||
b.Property<int?>("EpisodeRequestLimit");
|
||||
|
||||
b.Property<DateTime?>("LastLoggedIn");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<int?>("MovieRequestLimit");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("ProviderUserId");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserAccessToken");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<int>("UserType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("GrandparentKey");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GrandparentKey");
|
||||
|
||||
b.ToTable("PlexEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("PlexContentId");
|
||||
|
||||
b.Property<int?>("PlexServerContentId");
|
||||
|
||||
b.Property<int>("SeasonKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlexServerContentId");
|
||||
|
||||
b.ToTable("PlexSeasonsContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<string>("Quality");
|
||||
|
||||
b.Property<string>("ReleaseYear");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PlexServerContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RadarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<int>("ContentId");
|
||||
|
||||
b.Property<int>("ContentType");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RecentlyAddedLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<int>("ParentRequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("SeriesType");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentRequestId");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("ChildRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("IssueCategory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Comment");
|
||||
|
||||
b.Property<DateTime>("Date");
|
||||
|
||||
b.Property<int?>("IssuesId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssuesId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("IssueComments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<int>("IssueCategoryId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int?>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime?>("ResovledDate");
|
||||
|
||||
b.Property<int>("Status");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("UserReportedId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssueCategoryId");
|
||||
|
||||
b.HasIndex("IssueId");
|
||||
|
||||
b.HasIndex("UserReportedId");
|
||||
|
||||
b.ToTable("Issues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<DateTime?>("DigitalReleaseDate");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("RootPathOverride");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("MovieRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeCount");
|
||||
|
||||
b.Property<DateTime>("RequestDate");
|
||||
|
||||
b.Property<int>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RequestLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int?>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int?>("RootFolder");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("TvRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Token");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AirDate");
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("Requested");
|
||||
|
||||
b.Property<int>("SeasonId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SeasonId");
|
||||
|
||||
b.ToTable("EpisodeRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ChildRequestId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ChildRequestId");
|
||||
|
||||
b.ToTable("SeasonRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("ParentId")
|
||||
.HasPrincipalKey("EmbyId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("NotificationUserIds")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("GrandparentKey")
|
||||
.HasPrincipalKey("Key")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent")
|
||||
.WithMany("Seasons")
|
||||
.HasForeignKey("PlexServerContentId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
||||
.WithMany("ChildRequests")
|
||||
.HasForeignKey("ParentRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues")
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("IssuesId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory")
|
||||
.WithMany()
|
||||
.HasForeignKey("IssueCategoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.MovieRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserReportedId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("SeasonId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest")
|
||||
.WithMany("SeasonRequests")
|
||||
.HasForeignKey("ChildRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
69
src/Ombi.Store/Migrations/20180406224743_EmbyMetadata.cs
Normal file
69
src/Ombi.Store/Migrations/20180406224743_EmbyMetadata.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
public partial class EmbyMetadata : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "ImdbId",
|
||||
table: "EmbyEpisode",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "TheMovieDbId",
|
||||
table: "EmbyEpisode",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "TvDbId",
|
||||
table: "EmbyEpisode",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "ImdbId",
|
||||
table: "EmbyContent",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "TheMovieDbId",
|
||||
table: "EmbyContent",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "TvDbId",
|
||||
table: "EmbyContent",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ImdbId",
|
||||
table: "EmbyEpisode");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TheMovieDbId",
|
||||
table: "EmbyEpisode");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TvDbId",
|
||||
table: "EmbyEpisode");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ImdbId",
|
||||
table: "EmbyContent");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TheMovieDbId",
|
||||
table: "EmbyContent");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TvDbId",
|
||||
table: "EmbyContent");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -185,10 +185,16 @@ namespace Ombi.Store.Migrations
|
|||
b.Property<string>("EmbyId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
@ -207,14 +213,20 @@ namespace Ombi.Store.Migrations
|
|||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ParentId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentId");
|
||||
|
|
|
@ -35,42 +35,28 @@ using Ombi.Store.Entities;
|
|||
|
||||
namespace Ombi.Store.Repository
|
||||
{
|
||||
public class EmbyContentRepository : IEmbyContentRepository
|
||||
public class EmbyContentRepository : Repository<EmbyContent>, IEmbyContentRepository
|
||||
{
|
||||
|
||||
public EmbyContentRepository(IOmbiContext db)
|
||||
public EmbyContentRepository(IOmbiContext db):base(db)
|
||||
{
|
||||
Db = db;
|
||||
}
|
||||
|
||||
private IOmbiContext Db { get; }
|
||||
|
||||
public IQueryable<EmbyContent> GetAll()
|
||||
|
||||
public async Task<EmbyContent> GetByImdbId(string imdbid)
|
||||
{
|
||||
return Db.EmbyContent.AsQueryable();
|
||||
return await Db.EmbyContent.FirstOrDefaultAsync(x => x.ImdbId == imdbid);
|
||||
}
|
||||
|
||||
public async Task AddRange(IEnumerable<EmbyContent> content)
|
||||
public async Task<EmbyContent> GetByTvDbId(string tv)
|
||||
{
|
||||
Db.EmbyContent.AddRange(content);
|
||||
await Db.SaveChangesAsync();
|
||||
return await Db.EmbyContent.FirstOrDefaultAsync(x => x.TvDbId == tv);
|
||||
}
|
||||
|
||||
public async Task<bool> ContentExists(string providerId)
|
||||
public async Task<EmbyContent> GetByTheMovieDbId(string mov)
|
||||
{
|
||||
return await Db.EmbyContent.AnyAsync(x => x.ProviderId == providerId);
|
||||
}
|
||||
|
||||
public async Task<EmbyContent> Add(EmbyContent content)
|
||||
{
|
||||
await Db.EmbyContent.AddAsync(content);
|
||||
await Db.SaveChangesAsync();
|
||||
return content;
|
||||
}
|
||||
|
||||
public async Task<EmbyContent> Get(string providerId)
|
||||
{
|
||||
return await Db.EmbyContent.FirstOrDefaultAsync(x => x.ProviderId == providerId);
|
||||
return await Db.EmbyContent.FirstOrDefaultAsync(x => x.TheMovieDbId == mov);
|
||||
}
|
||||
|
||||
public IQueryable<EmbyContent> Get()
|
||||
|
@ -111,23 +97,9 @@ namespace Ombi.Store.Repository
|
|||
await Db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private bool _disposed;
|
||||
protected virtual void Dispose(bool disposing)
|
||||
public void UpdateWithoutSave(EmbyContent existingContent)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
Db?.Dispose();
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
Db.EmbyContent.Update(existingContent);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,19 +6,19 @@ using Ombi.Store.Entities;
|
|||
|
||||
namespace Ombi.Store.Repository
|
||||
{
|
||||
public interface IEmbyContentRepository : IDisposable
|
||||
public interface IEmbyContentRepository : IRepository<EmbyContent>
|
||||
{
|
||||
Task<EmbyContent> Add(EmbyContent content);
|
||||
Task AddRange(IEnumerable<EmbyContent> content);
|
||||
Task<bool> ContentExists(string providerId);
|
||||
IQueryable<EmbyContent> Get();
|
||||
Task<EmbyContent> Get(string providerId);
|
||||
IQueryable<EmbyContent> GetAll();
|
||||
Task<EmbyContent> GetByTheMovieDbId(string mov);
|
||||
Task<EmbyContent> GetByTvDbId(string tv);
|
||||
Task<EmbyContent> GetByImdbId(string imdbid);
|
||||
Task<EmbyContent> GetByEmbyId(string embyId);
|
||||
Task Update(EmbyContent existingContent);
|
||||
IQueryable<EmbyEpisode> GetAllEpisodes();
|
||||
Task<EmbyEpisode> Add(EmbyEpisode content);
|
||||
Task<EmbyEpisode> GetEpisodeByEmbyId(string key);
|
||||
Task AddRange(IEnumerable<EmbyEpisode> content);
|
||||
|
||||
void UpdateWithoutSave(EmbyContent existingContent);
|
||||
}
|
||||
}
|
|
@ -58,10 +58,11 @@ const routes: Routes = [
|
|||
// AoT requires an exported function for factories
|
||||
export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLocation) {
|
||||
const base = platformLocation.getBaseHrefFromDOM();
|
||||
const version = Math.floor(Math.random() * 999999999);
|
||||
if (base.length > 1) {
|
||||
return new TranslateHttpLoader(http, `${base}/translations/`, ".json");
|
||||
return new TranslateHttpLoader(http, `${base}/translations/`, `.json?v=${version}`);
|
||||
}
|
||||
return new TranslateHttpLoader(http, "/translations/", ".json");
|
||||
return new TranslateHttpLoader(http, "/translations/", `.json?v=${version}`);
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -57,6 +57,9 @@ export interface IDiscordNotifcationSettings extends INotificationSettings {
|
|||
|
||||
export interface INewsletterNotificationSettings extends INotificationSettings {
|
||||
notificationTemplate: INotificationTemplates;
|
||||
disableMovies: boolean;
|
||||
disableTv: boolean;
|
||||
externalEmails: string[];
|
||||
}
|
||||
|
||||
export interface ITelegramNotifcationSettings extends INotificationSettings {
|
||||
|
|
|
@ -30,3 +30,20 @@ export interface ISearchTvResult {
|
|||
firstSeason: boolean;
|
||||
latestSeason: boolean;
|
||||
}
|
||||
|
||||
export interface ITvRequestViewModel {
|
||||
requestAll: boolean;
|
||||
firstSeason: boolean;
|
||||
latestSeason: boolean;
|
||||
tvDbId: number;
|
||||
seasons: ISeasonsViewModel[];
|
||||
}
|
||||
|
||||
export interface ISeasonsViewModel {
|
||||
seasonNumber: number;
|
||||
episodes: IEpisodesViewModel[];
|
||||
}
|
||||
|
||||
export interface IEpisodesViewModel {
|
||||
episodeNumber: number;
|
||||
}
|
||||
|
|
|
@ -1,79 +1,80 @@
|
|||
<div *ngIf="issue">
|
||||
<div class="myBg backdrop" [style.background-image]="backgroundPath"></div>
|
||||
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
|
||||
<h1>{{issue.title}} </h1>
|
||||
<div class="col-md-6">
|
||||
<img class="img-responsive poster" src="{{posterPath}}" alt="poster">
|
||||
<span class="label label-info">{{IssueStatus[issue.status]}}</span>
|
||||
<span class="label label-success">{{issue.issueCategory.value}}</span>
|
||||
<div class="row">
|
||||
<div class="myBg backdrop" [style.background-image]="backgroundPath"></div>
|
||||
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
|
||||
<h1>{{issue.title}} </h1>
|
||||
<div class="col-md-6">
|
||||
<img class="img-responsive poster" src="{{posterPath}}" alt="poster">
|
||||
<span class="label label-info">{{IssueStatus[issue.status]}}</span>
|
||||
<span class="label label-success">{{issue.issueCategory.value}}</span>
|
||||
|
||||
<h3 *ngIf="issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.alias}}</h3>
|
||||
<h3 *ngIf="!issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.userName}}</h3>
|
||||
<h3 *ngIf="issue.subject">{{'Issues.Subject' | translate}}: {{issue.subject}}</h3>
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<label for="description" class="control-label" [translate]="'Issues.Description'"></label>
|
||||
<div>
|
||||
<textarea class="form-control-custom form-control" disabled="disabled" [(ngModel)]="issue.description" rows="5" type="text"></textarea>
|
||||
<h3 *ngIf="issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.alias}}</h3>
|
||||
<h3 *ngIf="!issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.userName}}</h3>
|
||||
<h3 *ngIf="issue.subject">{{'Issues.Subject' | translate}}: {{issue.subject}}</h3>
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<label for="description" class="control-label" [translate]="'Issues.Description'"></label>
|
||||
<div>
|
||||
<textarea class="form-control-custom form-control" disabled="disabled" [(ngModel)]="issue.description" rows="5" type="text"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row chat-window col-xs-7 col-md-5" id="chat_window_1" style="margin-left:10px;">
|
||||
<div class="col-xs-12 col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading top-bar">
|
||||
<div class="col-md-8 col-xs-8">
|
||||
<h3 class="panel-title">
|
||||
<span class="glyphicon glyphicon-comment"></span> {{'Issues.Comments' | translate}}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="comments" class="panel-body msg_container_base">
|
||||
<div *ngIf="comments.length <= 0" class="row msg_container base_receive">
|
||||
<div class="col-md-10 col-xs-10">
|
||||
<div class="messages msg_sent">
|
||||
<p [translate]="'Issues.NoComments'"></p>
|
||||
</div>
|
||||
<div class="row chat-window col-xs-7 col-md-5" id="chat_window_1" style="margin-left:10px;">
|
||||
<div class="col-xs-12 col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading top-bar">
|
||||
<div class="col-md-8 col-xs-8">
|
||||
<h3 class="panel-title">
|
||||
<span class="glyphicon glyphicon-comment"></span> {{'Issues.Comments' | translate}}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let comment of comments" class="row msg_container" [ngClass]="{'base_sent': comment.adminComment, 'base_receive': !comment.adminComment}">
|
||||
<div class="col-md-10 col-xs-10">
|
||||
<div class="messages msg_sent">
|
||||
<p>{{comment.comment}}</p>
|
||||
<time>{{comment.username}} • {{comment.date | date:'short'}}</time>
|
||||
<div *ngIf="comments" class="panel-body msg_container_base">
|
||||
<div *ngIf="comments.length <= 0" class="row msg_container base_receive">
|
||||
<div class="col-md-10 col-xs-10">
|
||||
<div class="messages msg_sent">
|
||||
<p [translate]="'Issues.NoComments'"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<div class="input-group">
|
||||
<input id="btn-input" type="text" class="form-control input-sm chat_input" [(ngModel)]="newComment.comment" [attr.placeholder]="'Issues.WriteMessagePlaceholder' | translate" />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary btn-sm" id="btn-chat" (click)="addComment()" [translate]="'Issues.SendMessageButton'"></button>
|
||||
</span>
|
||||
<div *ngFor="let comment of comments" class="row msg_container" [ngClass]="{'base_sent': comment.adminComment, 'base_receive': !comment.adminComment}">
|
||||
<div class="col-md-10 col-xs-10">
|
||||
<div class="messages msg_sent">
|
||||
<p>{{comment.comment}}</p>
|
||||
<time>{{comment.username}} • {{comment.date | date:'short'}}</time>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<div class="input-group">
|
||||
<input id="btn-input" type="text" class="form-control input-sm chat_input" [(ngModel)]="newComment.comment" [attr.placeholder]="'Issues.WriteMessagePlaceholder' | translate" />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary btn-sm" id="btn-chat" (click)="addComment()" [translate]="'Issues.SendMessageButton'"></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div *ngIf="isAdmin && settings">
|
||||
<div *ngIf="issue.status === IssueStatus.Pending && settings.enableInProgress">
|
||||
<button class="btn btn-primary btn-sm" (click)="inProgress()" [translate]="'Issues.MarkInProgress'"></button>
|
||||
</div>
|
||||
<div *ngIf="issue.status === IssueStatus.Pending && !settings.enableInProgress || issue.status == IssueStatus.InProgress">
|
||||
<button class="btn btn-primary btn-sm" (click)="resolve()" [translate]="'Issues.MarkResolved'"></button>
|
||||
<div class="col-md-12">
|
||||
<div *ngIf="isAdmin && settings">
|
||||
<div *ngIf="issue.status === IssueStatus.Pending && settings.enableInProgress">
|
||||
<button class="btn btn-primary btn-sm bottom-btn" (click)="inProgress()" [translate]="'Issues.MarkInProgress'"></button>
|
||||
</div>
|
||||
<div *ngIf="issue.status === IssueStatus.Pending && !settings.enableInProgress || issue.status == IssueStatus.InProgress">
|
||||
<button class="btn btn-primary btn-sm bottom-btn" (click)="resolve()" [translate]="'Issues.MarkResolved'"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -70,8 +70,9 @@ body{
|
|||
.tint {
|
||||
z-index: -1;
|
||||
}
|
||||
img-responsive poster {
|
||||
display:block;
|
||||
.img-responsive.poster {
|
||||
margin-bottom: 21px;
|
||||
width: 50%;
|
||||
}
|
||||
img {
|
||||
display: block;
|
||||
|
@ -143,4 +144,8 @@ img {
|
|||
border-top: 1px solid transparent;
|
||||
border-bottom-right-radius: -1;
|
||||
border-bottom-left-radius: -1;
|
||||
}
|
||||
|
||||
.bottom-btn{
|
||||
margin-bottom: 10px;
|
||||
}
|
|
@ -14,32 +14,32 @@
|
|||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
|
||||
<li>
|
||||
<a (click)="setOrder('requestedDate')">{{ 'Requests.SortRequestDate' | translate }}
|
||||
<a class="active" (click)="setOrder('requestedDate', $event)">{{ 'Requests.SortRequestDate' | translate }}
|
||||
<span *ngIf="order === 'requestedDate'">
|
||||
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||
</span>
|
||||
</a>
|
||||
<a (click)="setOrder('title')">{{ 'Requests.SortTitle' | translate}}
|
||||
<a (click)="setOrder('title', $event)">{{ 'Requests.SortTitle' | translate}}
|
||||
<span *ngIf="order === 'title'">
|
||||
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||
</span>
|
||||
</a>
|
||||
<a (click)="setOrder('releaseDate')">{{ 'Requests.TheatricalReleaseSort' | translate }}
|
||||
<a (click)="setOrder('releaseDate', $event)">{{ 'Requests.TheatricalReleaseSort' | translate }}
|
||||
<span *ngIf="order === 'releaseDate'">
|
||||
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||
</span>
|
||||
</a>
|
||||
<a (click)="setOrder('requestedUser.userAlias')">{{ 'Requests.SortRequestedBy' | translate }}
|
||||
<a (click)="setOrder('requestedUser.userAlias', $event)">{{ 'Requests.SortRequestedBy' | translate }}
|
||||
<span *ngIf="order === 'requestedUser.userAlias'">
|
||||
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a (click)="setOrder('status')">{{ 'Requests.SortStatus' | translate }}
|
||||
<a (click)="setOrder('status', $event)">{{ 'Requests.SortStatus' | translate }}
|
||||
<span *ngIf="order === 'status'">
|
||||
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||
|
@ -78,40 +78,42 @@
|
|||
</a>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<span>{{ 'Requests.RequestedBy' | translate }} </span>
|
||||
<span *ngIf="!isAdmin">{{request.requestedUser.userName}}</span>
|
||||
<span *ngIf="isAdmin && request.requestedUser.alias">{{request.requestedUser.alias}}</span>
|
||||
<span *ngIf="isAdmin && !request.requestedUser.alias">{{request.requestedUser.userName}}</span>
|
||||
<div class="request-info">
|
||||
<div class="request-by">
|
||||
<span>{{ 'Requests.RequestedBy' | translate }} </span>
|
||||
<span *ngIf="!isAdmin">{{request.requestedUser.userName}}</span>
|
||||
<span *ngIf="isAdmin && request.requestedUser.alias">{{request.requestedUser.alias}}</span>
|
||||
<span *ngIf="isAdmin && !request.requestedUser.alias">{{request.requestedUser.userName}}</span>
|
||||
</div>
|
||||
<div class="request-status">
|
||||
<span>{{ 'Requests.Status' | translate }} </span>
|
||||
<span class="label label-success" id="requestedStatusLabel">{{request.status}}</span>
|
||||
</div>
|
||||
|
||||
<div class="requested-status">
|
||||
<span>{{ 'Requests.RequestStatus' | translate }} </span>
|
||||
<span *ngIf="request.available" class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span>
|
||||
<span *ngIf="request.approved && !request.available" id="processingRequestLabel" class="label label-info" [translate]="'Common.ProcessingRequest'"></span>
|
||||
<span *ngIf="request.denied" class="label label-danger" id="requestDeclinedLabel" [translate]="'Common.RequestDenied'"></span>
|
||||
<span *ngIf="request.deniedReason" title="{{request.deniedReason}}">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</span>
|
||||
<span *ngIf="!request.approved && !request.availble && !request.denied" id="pendingApprovalLabel" class="label label-warning"
|
||||
[translate]="'Common.PendingApproval'"></span>
|
||||
|
||||
</div>
|
||||
<div *ngIf="request.denied" id="requestDenied">
|
||||
{{ 'Requests.Denied' | translate }}
|
||||
<i style="color:red;" class="fa fa-check"></i>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="releaseDate">{{ 'Requests.TheatricalRelease' | translate: {date: request.releaseDate | date: 'mediumDate'} }}</div>
|
||||
<div *ngIf="request.digitalReleaseDate" id="digitalReleaseDate">{{ 'Requests.DigitalRelease' | translate: {date: request.digitalReleaseDate | date: 'mediumDate'} }}</div>
|
||||
<div id="requestedDate">{{ 'Requests.RequestDate' | translate }} {{request.requestedDate | date}}</div>
|
||||
<br />
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ 'Requests.Status' | translate }} </span>
|
||||
<span class="label label-success" id="requestedStatusLabel">{{request.status}}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>{{ 'Requests.RequestStatus' | translate }} </span>
|
||||
<span *ngIf="request.available" class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span>
|
||||
<span *ngIf="request.approved && !request.available" id="processingRequestLabel" class="label label-info" [translate]="'Common.ProcessingRequest'"></span>
|
||||
<span *ngIf="request.denied" class="label label-danger" id="requestDeclinedLabel" [translate]="'Common.RequestDenied'"></span>
|
||||
<span *ngIf="request.deniedReason" title="{{request.deniedReason}}">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</span>
|
||||
<span *ngIf="!request.approved && !request.availble && !request.denied" id="pendingApprovalLabel" class="label label-warning"
|
||||
[translate]="'Common.PendingApproval'"></span>
|
||||
|
||||
</div>
|
||||
<div *ngIf="request.denied" id="requestDenied">
|
||||
{{ 'Requests.Denied' | translate }}
|
||||
<i style="color:red;" class="fa fa-check"></i>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="releaseDate">{{ 'Requests.TheatricalRelease' | translate: {date: request.releaseDate | date: 'mediumDate'} }}</div>
|
||||
<div *ngIf="request.digitalReleaseDate" id="digitalReleaseDate">{{ 'Requests.DigitalRelease' | translate: {date: request.digitalReleaseDate | date: 'mediumDate'} }}</div>
|
||||
<div id="requestedDate">{{ 'Requests.RequestDate' | translate }} {{request.requestedDate | date}}</div>
|
||||
<br />
|
||||
<div *ngIf="isAdmin">
|
||||
<div *ngIf="request.qualityOverrideTitle">{{ 'Requests.QualityOverride' | translate }}
|
||||
<span>{{request.qualityOverrideTitle}} </span>
|
||||
|
@ -127,13 +129,15 @@
|
|||
<div *ngIf="!request.approved" id="approveBtn">
|
||||
<form>
|
||||
<button (click)="approve(request)" style="text-align: right" class="btn btn-sm btn-success-outline approve" type="submit">
|
||||
<i class="fa fa-plus"></i> {{ 'Common.Approve' | translate }}</button>
|
||||
<i class="fa fa-plus"></i> {{ 'Common.Approve' | translate }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!--Radarr Root Folder-->
|
||||
<div *ngIf="radarrRootFolders" class="btn-group btn-split" id="rootFolderBtn">
|
||||
<button type="button" class="btn btn-sm btn-warning-outline">
|
||||
<i class="fa fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}</button>
|
||||
<i class="fa fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
|
@ -148,7 +152,8 @@
|
|||
<!--Radarr Quality Profiles -->
|
||||
<div *ngIf="radarrProfiles" class="btn-group btn-split" id="changeQualityBtn">
|
||||
<button type="button" class="btn btn-sm btn-warning-outline">
|
||||
<i class="fa fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}</button>
|
||||
<i class="fa fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
|
@ -162,19 +167,23 @@
|
|||
|
||||
<div *ngIf="!request.denied" id="denyBtn">
|
||||
<button type="button" (click)="deny(request)" class="btn btn-sm btn-danger-outline deny">
|
||||
<i class="fa fa-times"></i> {{ 'Requests.Deny' | translate }}</button>
|
||||
<i class="fa fa-times"></i> {{ 'Requests.Deny' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<form id="removeBtn">
|
||||
<button (click)="removeRequest(request)" style="text-align: right" class="btn btn-sm btn-danger-outline delete">
|
||||
<i class="fa fa-minus"></i> {{ 'Requests.Remove' | translate }}</button>
|
||||
<i class="fa fa-minus"></i> {{ 'Requests.Remove' | translate }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<form id="markBtnGroup">
|
||||
<button id="unavailableBtn" *ngIf="request.available" (click)="changeAvailability(request, false)" style="text-align: right" value="false" class="btn btn-sm btn-info-outline change">
|
||||
<i class="fa fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}</button>
|
||||
<i class="fa fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}
|
||||
</button>
|
||||
<button id="availableBtn" *ngIf="!request.available" (click)="changeAvailability(request, true)" style="text-align: right" value="true" class="btn btn-sm btn-success-outline change">
|
||||
<i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}</button>
|
||||
<i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
|
||||
|
@ -183,7 +192,7 @@
|
|||
|
||||
<div class="dropdown" *ngIf="issueCategories && issuesEnabled" id="issuesBtn">
|
||||
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
|
||||
aria-expanded="true">
|
||||
aria-expanded="true">
|
||||
<i class="fa fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
|
|
|
@ -175,11 +175,18 @@ export class MovieRequestsComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
public setOrder(value: string) {
|
||||
public setOrder(value: string, el: any) {
|
||||
el = el.toElement || el.relatedTarget || el.target || el.srcElement;
|
||||
|
||||
const parent = el.parentElement;
|
||||
const previousFilter = parent.querySelector(".active");
|
||||
|
||||
if (this.order === value) {
|
||||
this.reverse = !this.reverse;
|
||||
this.reverse = !this.reverse;
|
||||
} else {
|
||||
previousFilter.className = "";
|
||||
el.className = "active";
|
||||
}
|
||||
|
||||
this.order = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,19 @@ export class TvRequestsComponent implements OnInit {
|
|||
|
||||
public openClosestTab(el: any) {
|
||||
const rowclass = "undefined ng-star-inserted";
|
||||
el = el.toElement || el.relatedTarget || el.target;
|
||||
el = el.toElement || el.relatedTarget || el.target || el.srcElement;
|
||||
|
||||
if (el.nodeName === "BUTTON") {
|
||||
|
||||
const isButtonAlreadyActive = el.parentElement.querySelector(".active");
|
||||
// if a Button already has Class: .active
|
||||
if (isButtonAlreadyActive) {
|
||||
isButtonAlreadyActive.classList.remove("active");
|
||||
} else {
|
||||
el.className += " active";
|
||||
}
|
||||
}
|
||||
|
||||
while (el.className !== rowclass) {
|
||||
// Increment the loop to the parent node until we find the row we need
|
||||
el = el.parentNode;
|
||||
|
@ -90,12 +102,6 @@ export class TvRequestsComponent implements OnInit {
|
|||
}
|
||||
|
||||
public ngOnInit() {
|
||||
|
||||
const profile = <ISonarrProfile>{name:"test",id:1 };
|
||||
const folder = <ISonarrRootFolder>{path:"testpath", id:1};
|
||||
|
||||
this.sonarrProfiles.push(profile);
|
||||
this.sonarrRootFolders.push(folder);
|
||||
this.amountToLoad = 1000;
|
||||
this.currentlyLoaded = 1000;
|
||||
this.tvRequests = [];
|
||||
|
@ -204,7 +210,7 @@ export class TvRequestsComponent implements OnInit {
|
|||
this.loadInit();
|
||||
}
|
||||
private loadBackdrop(val: TreeNode): void {
|
||||
this.imageService.getTvBanner(val.data.id).subscribe(x => {
|
||||
this.imageService.getTvBanner(val.data.tvDbId).subscribe(x => {
|
||||
val.data.background = this.sanitizer.bypassSecurityTrustStyle
|
||||
("url(" + x + ")");
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@ import { NotificationService } from "../services";
|
|||
import { RequestService } from "../services";
|
||||
import { SearchService } from "../services";
|
||||
|
||||
import { INewSeasonRequests, IRequestEngineResult } from "../interfaces";
|
||||
import { INewSeasonRequests, IRequestEngineResult, ISeasonsViewModel, ITvRequestViewModel } from "../interfaces";
|
||||
import { IEpisodesRequests } from "../interfaces";
|
||||
import { ISearchTvResult } from "../interfaces";
|
||||
|
||||
|
@ -46,7 +46,22 @@ export class SeriesInformationComponent implements OnInit {
|
|||
|
||||
this.series.requested = true;
|
||||
|
||||
this.requestService.requestTv(this.series)
|
||||
const viewModel = <ITvRequestViewModel>{ firstSeason: this.series.firstSeason, latestSeason: this.series.latestSeason, requestAll: this.series.requestAll, tvDbId: this.series.id};
|
||||
viewModel.seasons = [];
|
||||
this.series.seasonRequests.forEach((season) => {
|
||||
const seasonsViewModel = <ISeasonsViewModel>{seasonNumber: season.seasonNumber, episodes: []};
|
||||
season.episodes.forEach(ep => {
|
||||
if(!this.series.latestSeason || !this.series.requestAll || !this.series.firstSeason) {
|
||||
if(ep.requested) {
|
||||
seasonsViewModel.episodes.push({episodeNumber: ep.episodeNumber});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
viewModel.seasons.push(seasonsViewModel);
|
||||
});
|
||||
|
||||
this.requestService.requestTv(viewModel)
|
||||
.subscribe(x => {
|
||||
this.result = x as IRequestEngineResult;
|
||||
if (this.result.result) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { ImageService, NotificationService, RequestService, SearchService} from
|
|||
|
||||
import { TreeNode } from "primeng/primeng";
|
||||
import { IRequestEngineResult } from "../interfaces";
|
||||
import { IIssueCategory, ISearchTvResult } from "../interfaces";
|
||||
import { IIssueCategory, ISearchTvResult, ISeasonsViewModel, ITvRequestViewModel } from "../interfaces";
|
||||
|
||||
@Component({
|
||||
selector: "tv-search",
|
||||
|
@ -154,7 +154,23 @@ export class TvSearchComponent implements OnInit {
|
|||
if (this.authService.hasRole("admin") || this.authService.hasRole("AutoApproveMovie")) {
|
||||
searchResult.approved = true;
|
||||
}
|
||||
this.requestService.requestTv(searchResult)
|
||||
|
||||
const viewModel = <ITvRequestViewModel>{ firstSeason: searchResult.firstSeason, latestSeason: searchResult.latestSeason, requestAll: searchResult.requestAll, tvDbId: searchResult.id};
|
||||
viewModel.seasons = [];
|
||||
searchResult.seasonRequests.forEach((season) => {
|
||||
const seasonsViewModel = <ISeasonsViewModel>{seasonNumber: season.seasonNumber, episodes: []};
|
||||
season.episodes.forEach(ep => {
|
||||
if(!searchResult.latestSeason || !searchResult.requestAll || !searchResult.firstSeason) {
|
||||
if(ep.requested) {
|
||||
seasonsViewModel.episodes.push({episodeNumber: ep.episodeNumber});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
viewModel.seasons.push(seasonsViewModel);
|
||||
});
|
||||
|
||||
this.requestService.requestTv(viewModel)
|
||||
.subscribe(x => {
|
||||
this.result = x;
|
||||
if (this.result.result) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Observable } from "rxjs/Rx";
|
|||
import { TreeNode } from "primeng/primeng";
|
||||
import { IRequestEngineResult } from "../interfaces";
|
||||
import { IChildRequests, IFilter, IMovieRequestModel, IMovieRequests, IMovieUpdateModel, ITvRequests, ITvUpdateModel } from "../interfaces";
|
||||
import { ISearchTvResult } from "../interfaces";
|
||||
import { ITvRequestViewModel } from "../interfaces";
|
||||
import { ServiceHelpers } from "./service.helpers";
|
||||
|
||||
@Injectable()
|
||||
|
@ -20,7 +20,7 @@ export class RequestService extends ServiceHelpers {
|
|||
return this.http.post<IRequestEngineResult>(`${this.url}Movie/`, JSON.stringify(movie), {headers: this.headers});
|
||||
}
|
||||
|
||||
public requestTv(tv: ISearchTvResult): Observable<IRequestEngineResult> {
|
||||
public requestTv(tv: ITvRequestViewModel): Observable<IRequestEngineResult> {
|
||||
return this.http.post<IRequestEngineResult>(`${this.url}TV/`, JSON.stringify(tv), {headers: this.headers});
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
<span>Discord</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://discord.gg/KxYZ64w" target="_blank">https://discord.gg/KxYZ64w</a>
|
||||
<a href="https://discord.gg/Sa7wNWb" target="_blank">https://discord.gg/</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -50,6 +50,22 @@
|
|||
<a href="https://www.reddit.com/r/Ombi/" target="_blank">https://www.reddit.com/r/Ombi/</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span>Issues</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://github.com/tidusjar/Ombi/issues" target="_blank">https://github.com/tidusjar/Ombi/issues</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span>Wiki</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://github.com/tidusjar/Ombi/wiki" target="_blank">https://github.com/tidusjar/Ombi/wiki</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span>OS Architecture</span>
|
||||
|
|
|
@ -28,8 +28,8 @@ export class JobsComponent implements OnInit {
|
|||
embyContentSync: [x.embyContentSync, Validators.required],
|
||||
plexContentSync: [x.plexContentSync, Validators.required],
|
||||
userImporter: [x.userImporter, Validators.required],
|
||||
sonarrSync: [x.radarrSync, Validators.required],
|
||||
radarrSync: [x.sonarrSync, Validators.required],
|
||||
sonarrSync: [x.sonarrSync, Validators.required],
|
||||
radarrSync: [x.radarrSync, Validators.required],
|
||||
sickRageSync: [x.sickRageSync, Validators.required],
|
||||
refreshMetadata: [x.refreshMetadata, Validators.required],
|
||||
newsletter: [x.newsletter, Validators.required],
|
||||
|
|
|
@ -9,6 +9,16 @@
|
|||
<div class="checkbox">
|
||||
<input type="checkbox" id="enabled" [(ngModel)]="settings.enabled" ng-checked="settings.enabled"><label for="enabled">Enable</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="disableTv" [(ngModel)]="settings.disableTv" ng-checked="settings.disableTv"><label for="disableTv">Disable TV</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="disableMovies" [(ngModel)]="settings.disableMovies" ng-checked="settings.disableMovies"><label for="disableMovies">Disable Movies</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">Subject</label>
|
||||
|
@ -43,6 +53,31 @@
|
|||
<br/>
|
||||
<small>When testing, the test newsletter will go to all users that have the Admin role, please ensure that there are valid email addresses for this. The test will also only grab the latest 10 movies and 10 shows just to give you an example.</small>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-12">
|
||||
<label for="emailToAdd" class="control-label">Add External Email (For users that are not in Ombi)</label>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<input type="text" [(ngModel)]="emailToAdd" class="form-control form-control-custom " id="emailToAdd"
|
||||
email name="emailToAdd" value="{{emailToAdd}}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<button class="btn btn-primary-outline" (click)="addEmail()" pTooltip="Don't forget to press the Submit button!">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div *ngFor="let email of settings.externalEmails">
|
||||
<div class="col-md-9">
|
||||
{{email}}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<button class="btn btn-sm btn-danger-outline" (click)="deleteEmail(email)">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
|
@ -11,6 +11,7 @@ export class NewsletterComponent implements OnInit {
|
|||
|
||||
public NotificationType = NotificationType;
|
||||
public settings: INewsletterNotificationSettings;
|
||||
public emailToAdd: string;
|
||||
|
||||
constructor(private settingsService: SettingsService,
|
||||
private notificationService: NotificationService,
|
||||
|
@ -48,4 +49,24 @@ export class NewsletterComponent implements OnInit {
|
|||
});
|
||||
|
||||
}
|
||||
public addEmail() {
|
||||
|
||||
if(this.emailToAdd) {
|
||||
const emailRegex = "[a-zA-Z0-9.-_]{1,}@[a-zA-Z.-]{2,}[.]{1}[a-zA-Z]{2,}";
|
||||
const match = this.emailToAdd.match(emailRegex)!;
|
||||
if(match && match.length > 0) {
|
||||
this.settings.externalEmails.push(this.emailToAdd);
|
||||
this.emailToAdd = "";
|
||||
} else {
|
||||
this.notificationService.error("Please enter a valid email address");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public deleteEmail(email: string) {
|
||||
const index = this.settings.externalEmails.indexOf(email); // <-- Not supported in <IE9
|
||||
if (index !== -1) {
|
||||
this.settings.externalEmails.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +1,70 @@
|
|||
<div *ngIf="user">
|
||||
<h3>User: {{user.userName}}</h3>
|
||||
<button type="button" class="btn btn-primary-outline" style="float:right;" [routerLink]="['/usermanagement/']">Back</button>
|
||||
<div class="user-details">
|
||||
<h3>User: {{user.userName}}</h3>
|
||||
<button type="button" class="btn btn-primary-outline" style="float:right;" [routerLink]="['/usermanagement/']">Back</button>
|
||||
|
||||
|
||||
<p-confirmDialog></p-confirmDialog>
|
||||
|
||||
<div class="modal-body" style="margin-top: 45px;">
|
||||
<div class="col-md-6">
|
||||
<h4>User Details</h4>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h4>Roles</h4>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="username" class="control-label">Username</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.userName" [readonly]="true" class="form-control form-control-custom " id="username" name="username" value="{{user?.userName}}">
|
||||
</div>
|
||||
<p-confirmDialog></p-confirmDialog>
|
||||
|
||||
<div class="modal-body" style="margin-top: 45px;">
|
||||
<div class="col-md-6">
|
||||
<h4>User Details</h4>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="alias" class="control-label">Alias</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.alias" class="form-control form-control-custom " id="alias" name="alias" value="{{user?.alias}}">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h4>Roles</h4>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="emailAddress" class="control-label">Email Address</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.emailAddress" class="form-control form-control-custom " id="emailAddress" name="emailAddress" value="{{user?.emailAddress}}" [disabled]="user?.userType == 2">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div *ngFor="let c of user.claims">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" [(ngModel)]="c.enabled" [value]="c.value" id="create{{c.value}}" [attr.name]="'create' + c.value" ng-checked="c.enabled">
|
||||
<label for="create{{c.value}}">{{c.value | humanize}}</label>
|
||||
<label for="username" class="control-label">Username</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.userName" [readonly]="true" class="form-control form-control-custom " id="username" name="username" value="{{user?.userName}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="alias" class="control-label">Alias</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.alias" class="form-control form-control-custom " id="alias" name="alias" value="{{user?.alias}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="emailAddress" class="control-label">Email Address</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.emailAddress" class="form-control form-control-custom " id="emailAddress" name="emailAddress" value="{{user?.emailAddress}}" [disabled]="user?.userType == 2">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="movieRequestLimit" class="control-label">Movie Request Limit</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.movieRequestLimit" class="form-control form-small form-control-custom " id="movieRequestLimit" name="movieRequestLimit" value="{{user?.movieRequestLimit}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="episodeRequestLimit" class="control-label">Episode Request Limit</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.episodeRequestLimit" class="form-control form-small form-control-custom " id="episodeRequestLimit" name="episodeRequestLimit" value="{{user?.episodeRequestLimit}}">
|
||||
<div class="col-md-6">
|
||||
<div *ngFor="let c of user.claims">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" [(ngModel)]="c.enabled" [value]="c.value" id="create{{c.value}}" [attr.name]="'create' + c.value" ng-checked="c.enabled">
|
||||
<label for="create{{c.value}}">{{c.value | humanize}}</label>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="movieRequestLimit" class="control-label">Movie Request Limit</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.movieRequestLimit" class="form-control form-small form-control-custom " id="movieRequestLimit" name="movieRequestLimit" value="{{user?.movieRequestLimit}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="episodeRequestLimit" class="control-label">Episode Request Limit</label>
|
||||
<div>
|
||||
<input type="text" [(ngModel)]="user.episodeRequestLimit" class="form-control form-small form-control-custom " id="episodeRequestLimit" name="episodeRequestLimit" value="{{user?.episodeRequestLimit}}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="btn btn-primary-outline" (click)="update()">Update</button>
|
||||
<button type="button" class="btn btn-danger-outline" (click)="delete()">Delete</button>
|
||||
<button type="button" style="float:right;" class="btn btn-info-outline" (click)="resetPassword()" pTooltip="You need your SMTP settings setup">Send Reset Password Link</button>
|
||||
<div>
|
||||
<button type="button" class="btn btn-primary-outline" (click)="update()">Update</button>
|
||||
<button type="button" class="btn btn-danger-outline" (click)="delete()">Delete</button>
|
||||
<button type="button" style="float:right;" class="btn btn-info-outline" (click)="resetPassword()" pTooltip="You need your SMTP settings setup">Send Reset Password Link</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -16,7 +16,7 @@
|
|||
</td>
|
||||
</a>
|
||||
</th>
|
||||
<th (click)="setOrder('userName')">
|
||||
<th class="active" (click)="setOrder('userName', $event)">
|
||||
<a>
|
||||
Username
|
||||
</a>
|
||||
|
@ -24,7 +24,7 @@
|
|||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||
</span>
|
||||
</th>
|
||||
<th (click)="setOrder('alias')">
|
||||
<th (click)="setOrder('alias', $event)">
|
||||
<a>
|
||||
Alias
|
||||
</a>
|
||||
|
@ -32,7 +32,7 @@
|
|||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||
</span>
|
||||
</th>
|
||||
<th (click)="setOrder('emailAddress')">
|
||||
<th (click)="setOrder('emailAddress', $event)">
|
||||
<a>
|
||||
Email
|
||||
</a>
|
||||
|
@ -44,13 +44,13 @@
|
|||
<th>
|
||||
Roles
|
||||
</th>
|
||||
<th (click)="setOrder('lastLoggedIn')">
|
||||
<th (click)="setOrder('lastLoggedIn', $event)">
|
||||
<a> Last Logged In</a>
|
||||
<span *ngIf="order === 'lastLoggedIn'">
|
||||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||
</span>
|
||||
</th>
|
||||
<th (click)="setOrder('userType')">
|
||||
<th (click)="setOrder('userType', $event)">
|
||||
<a>
|
||||
User Type
|
||||
</a>
|
||||
|
|
|
@ -93,9 +93,21 @@ export class UserManagementComponent implements OnInit {
|
|||
this.bulkEpisodeLimit = undefined;
|
||||
}
|
||||
|
||||
public setOrder(value: string) {
|
||||
public setOrder(value: string, el: any) {
|
||||
el = el.toElement || el.relatedTarget || el.target || el.srcElement;
|
||||
|
||||
if (el.nodeName === "A") {
|
||||
el = el.parentElement;
|
||||
}
|
||||
|
||||
const parent = el.parentElement;
|
||||
const previousFilter = parent.querySelector(".active");
|
||||
|
||||
if (this.order === value) {
|
||||
this.reverse = !this.reverse;
|
||||
this.reverse = !this.reverse;
|
||||
} else {
|
||||
previousFilter.className = "";
|
||||
el.className = "active";
|
||||
}
|
||||
|
||||
this.order = value;
|
||||
|
|
|
@ -126,6 +126,7 @@ legend {
|
|||
box-shadow: 0px 0px 0px 3px rgba(0, 0, 0, 0.2);
|
||||
}*/
|
||||
|
||||
|
||||
.navbar-default {
|
||||
background-color: #0a0a0a;
|
||||
border-color: #0a0a0a;
|
||||
|
@ -348,4 +349,7 @@ button.list-group-item:focus {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
table.table > thead > tr > th.active {
|
||||
background-color: transparent;
|
||||
}
|
|
@ -10,6 +10,8 @@ $danger-colour: #d9534f;
|
|||
$success-colour: #5cb85c;
|
||||
$i: !important;
|
||||
|
||||
|
||||
|
||||
@media (min-width: 768px ) {
|
||||
.bottom-align-text {
|
||||
position: absolute;
|
||||
|
@ -131,6 +133,10 @@ h1 {
|
|||
font-size: 1.9rem $i;
|
||||
}
|
||||
|
||||
a.active {
|
||||
background-color: $primary-colour;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.1rem $i;
|
||||
}
|
||||
|
@ -947,4 +953,5 @@ a > h4:hover {
|
|||
|
||||
.searchWidth {
|
||||
width: 94%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -283,6 +283,7 @@ namespace Ombi.Controllers
|
|||
notificationModel.Substitutes.Add("IssueStatus", issue.Status.ToString());
|
||||
notificationModel.Substitutes.Add("IssueSubject", issue.Subject);
|
||||
notificationModel.Substitutes.Add("IssueUser", issueReportedUsername);
|
||||
notificationModel.Substitutes.Add("RequestType", notificationModel.RequestType.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -174,7 +174,7 @@ namespace Ombi.Controllers
|
|||
/// <param name="tv">The tv.</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("tv")]
|
||||
public async Task<RequestEngineResult> RequestTv([FromBody] SearchTvShowViewModel tv)
|
||||
public async Task<RequestEngineResult> RequestTv([FromBody] TvRequestViewModel tv)
|
||||
{
|
||||
return await TvRequestEngine.RequestTvShow(tv);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
<Version>$(FullVer)</Version>
|
||||
<PackageVersion></PackageVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ServerGarbageCollection>false</ServerGarbageCollection>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netcoreapp2.0\Swagger.xml</DocumentationFile>
|
||||
<NoWarn>1701;1702;1705;1591;</NoWarn>
|
||||
|
|
|
@ -67,11 +67,27 @@ namespace Ombi
|
|||
}
|
||||
}
|
||||
|
||||
DeleteSchedulesDb();
|
||||
|
||||
Console.WriteLine($"We are running on {urlValue}");
|
||||
|
||||
BuildWebHost(args).Run();
|
||||
}
|
||||
|
||||
private static void DeleteSchedulesDb()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists("Schedules.db"))
|
||||
{
|
||||
File.Delete("Schedules.db");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static IWebHost BuildWebHost(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>()
|
||||
|
@ -98,9 +114,9 @@ namespace Ombi
|
|||
" Use \"*\" to indicate that the server should listen for requests on any IP address or hostname using the specified port and protocol (for example, http://*:5000). " +
|
||||
"The protocol (http:// or https://) must be included with each URL. Supported formats vary between servers.", Default = "http://*:5000")]
|
||||
public string Host { get; set; }
|
||||
|
||||
|
||||
[Option("storage", Required = false, HelpText = "Storage path, where we save the logs and database")]
|
||||
public string StoragePath { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ using Hangfire;
|
|||
using Hangfire.Console;
|
||||
using Hangfire.Dashboard;
|
||||
using Hangfire.SQLite;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
@ -44,7 +45,7 @@ namespace Ombi
|
|||
Console.WriteLine(env.ContentRootPath);
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", false, true)
|
||||
.AddJsonFile("appsettings.json", false, false)
|
||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
|
||||
.AddEnvironmentVariables();
|
||||
Configuration = builder.Build();
|
||||
|
@ -85,7 +86,7 @@ namespace Ombi
|
|||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
TelemetryConfiguration.Active.DisableTelemetry = true;
|
||||
// Add framework services.
|
||||
services.AddDbContext<OmbiContext>();
|
||||
|
||||
|
@ -183,12 +184,12 @@ namespace Ombi
|
|||
Authorization = new[] { new HangfireAuthorizationFilter() }
|
||||
});
|
||||
GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute { Attempts = 3 });
|
||||
|
||||
|
||||
// Setup the scheduler
|
||||
var jobSetup = app.ApplicationServices.GetService<IJobSetup>();
|
||||
jobSetup.Setup();
|
||||
ctx.Seed();
|
||||
|
||||
|
||||
var provider = new FileExtensionContentTypeProvider { Mappings = { [".map"] = "application/octet-stream" } };
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions()
|
||||
|
@ -218,6 +219,8 @@ namespace Ombi
|
|||
name: "spa-fallback",
|
||||
defaults: new { controller = "Home", action = "Index" });
|
||||
});
|
||||
|
||||
ombiService.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -168,6 +168,7 @@ namespace Ombi
|
|||
if (user == null)
|
||||
{
|
||||
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
context.Response.RegisterForDispose(um);
|
||||
await context.Response.WriteAsync("Invalid User Access Token");
|
||||
}
|
||||
else
|
||||
|
@ -177,6 +178,7 @@ namespace Ombi
|
|||
var roles = await um.GetRolesAsync(user);
|
||||
var principal = new GenericPrincipal(identity, roles.ToArray());
|
||||
context.User = principal;
|
||||
context.Response.RegisterForDispose(um);
|
||||
await next();
|
||||
}
|
||||
}
|
||||
|
@ -189,6 +191,7 @@ namespace Ombi
|
|||
if (!valid)
|
||||
{
|
||||
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
context.Response.RegisterForDispose(settingsProvider);
|
||||
await context.Response.WriteAsync("Invalid API Key");
|
||||
}
|
||||
else
|
||||
|
@ -196,6 +199,7 @@ namespace Ombi
|
|||
var identity = new GenericIdentity("API");
|
||||
var principal = new GenericPrincipal(identity, new[] { "Admin", "ApiUser" });
|
||||
context.User = principal;
|
||||
context.Response.RegisterForDispose(settingsProvider);
|
||||
await next();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,12 +63,13 @@ O:::::::OOO:::::::Om::::m m::::m m::::mb:::::bbbbbb::::::bi::::::i
|
|||
<meta name="description" content="Ombi, media request tool">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>@appName</title>
|
||||
<meta property="og:title" content=“@appName”/>
|
||||
<meta property="og:image" content="~/images/logo.png"/>
|
||||
<meta property="og:site_name" content=“@appName”/>
|
||||
<base href="/@baseUrl"/>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="~/images/favicon/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="~/images/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="~/images/favicon/favicon-16x16.png">
|
||||
<link rel="manifest" href="~/images/favicon/site.webmanifest">
|
||||
<link rel="mask-icon" href="~/images/favicon/safari-pinned-tab.svg" color="#df691a">
|
||||
<link rel="shortcut icon" href="~/images/favicon/favicon.ico">
|
||||
<meta name="msapplication-TileColor" content="#df691a">
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
SERVICE="Ombi"
|
||||
# change directory to location of project.json
|
||||
pushd ./
|
||||
# run dotnet publish, specify release build
|
||||
dotnet publish -c Release
|
||||
# equivalent to cd .. (go back to previous directory)
|
||||
#popd
|
||||
# Create a docker image tagged with the name of the project:latest
|
||||
docker build -t "$SERVICE":latest .
|
||||
# Check to see if this container exists.
|
||||
CONTAINER=`docker ps --all | grep "$SERVICE"`
|
||||
# if it doesn't, then just run this.
|
||||
if [ -z "$CONTAINER" ]; then
|
||||
docker run -i -p 8000:5000 --name $SERVICE -t $SERVICE:latest
|
||||
# if it does exist; nuke it and then run the new one
|
||||
else
|
||||
docker rm $SERVICE
|
||||
docker run -i -p 8000:5000 --name $SERVICE -t $SERVICE:latest
|
||||
fi
|
||||
|
||||
read -p "Press enter to continue"
|
963
src/Ombi/package-lock.json
generated
963
src/Ombi/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -21,11 +21,7 @@
|
|||
"Request": "Anmod",
|
||||
"Denied": "Afvist",
|
||||
"Approve": "Godkendt",
|
||||
<<<<<<< HEAD
|
||||
"PartlyAvailable": "Delvist tilgængelig",
|
||||
=======
|
||||
"PartlyAvailable": "Partly Available",
|
||||
>>>>>>> New translations en.json (Danish)
|
||||
"Errors": {
|
||||
"Validation": "Tjek venligst dine indtastede værdier"
|
||||
}
|
||||
|
@ -91,7 +87,6 @@
|
|||
"Trailer": "Trailer"
|
||||
},
|
||||
"TvShows": {
|
||||
<<<<<<< HEAD
|
||||
"Popular": "Populære",
|
||||
"Trending": "Aktuelle",
|
||||
"MostWatched": "Mest sete",
|
||||
|
@ -105,18 +100,6 @@
|
|||
"SubmitRequest": "Send anmodning",
|
||||
"Season": "Sæson: {{seasonNumber}}",
|
||||
"SelectAllInSeason": "Vælg alle i sæson {{seasonNumber}}"
|
||||
=======
|
||||
"Popular": "Popular",
|
||||
"Trending": "Trending",
|
||||
"MostWatched": "Most Watched",
|
||||
"MostAnticipated": "Most Anticipated",
|
||||
"Results": "Results",
|
||||
"AirDate": "Air Date:",
|
||||
"AllSeasons": "All Seasons",
|
||||
"FirstSeason": "First Season",
|
||||
"LatestSeason": "Latest Season",
|
||||
"Select": "Select ..."
|
||||
>>>>>>> New translations en.json (Danish)
|
||||
}
|
||||
},
|
||||
"Requests": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue