mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 21:33:15 -07:00
Merge pull request #1362 from tidusjar/EAP
Rework sonarr and newsletter fixes
This commit is contained in:
commit
574fc3841c
22 changed files with 649 additions and 89 deletions
|
@ -56,5 +56,8 @@ namespace Ombi.Api.Interfaces
|
|||
Series UpdateSeries(Series series, string apiKey, Uri baseUrl);
|
||||
SonarrSeasonSearchResult SearchForSeason(int seriesId, int seasonNumber, string apiKey, Uri baseUrl);
|
||||
SonarrSeriesSearchResult SearchForSeries(int seriesId, string apiKey, Uri baseUrl);
|
||||
|
||||
|
||||
SonarrAddSeries AddSeries(SonarrAddSeries series, string apiKey, Uri baseUrl);
|
||||
}
|
||||
}
|
|
@ -148,6 +148,42 @@ namespace Ombi.Api
|
|||
return result;
|
||||
}
|
||||
|
||||
public SonarrAddSeries AddSeries(SonarrAddSeries series,string apiKey, Uri baseUrl)
|
||||
{
|
||||
|
||||
var request = new RestRequest
|
||||
{
|
||||
Resource = "/api/Series?",
|
||||
Method = Method.POST
|
||||
};
|
||||
|
||||
Log.Debug("Sonarr API Options:");
|
||||
Log.Debug(series.DumpJson());
|
||||
|
||||
request.AddHeader("X-Api-Key", apiKey);
|
||||
request.AddJsonBody(series);
|
||||
|
||||
SonarrAddSeries result;
|
||||
try
|
||||
{
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling AddSeries for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
||||
TimeSpan.FromSeconds (2)
|
||||
});
|
||||
|
||||
result = policy.Execute(() => Api.ExecuteJson<SonarrAddSeries>(request, baseUrl));
|
||||
}
|
||||
catch (JsonSerializationException jse)
|
||||
{
|
||||
Log.Error(jse);
|
||||
var error = Api.ExecuteJson<List<SonarrError>>(request, baseUrl);
|
||||
var messages = error?.Select(x => x.errorMessage).ToList();
|
||||
messages?.ForEach(x => Log.Error(x));
|
||||
result = new SonarrAddSeries { ErrorMessages = messages };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public SonarrAddSeries AddSeriesNew(int tvdbId, string title, int qualityId, bool seasonFolders, string rootPath, int[] seasons, string apiKey, Uri baseUrl, bool monitor = true, bool searchForMissingEpisodes = false)
|
||||
{
|
||||
var request = new RestRequest
|
||||
|
@ -244,7 +280,18 @@ namespace Ombi.Api
|
|||
TimeSpan.FromSeconds(5)
|
||||
});
|
||||
|
||||
return policy.Execute(() => Api.ExecuteJson<List<Series>>(request, baseUrl));
|
||||
var series = policy.Execute(() => Api.ExecuteJson<List<Series>>(request, baseUrl));
|
||||
|
||||
// Remove the 'specials from the object'
|
||||
foreach (var s in series)
|
||||
{
|
||||
var seasonToRemove = s.seasons.FirstOrDefault(x => x.seasonNumber == 0);
|
||||
if (seasonToRemove != null)
|
||||
{
|
||||
s.seasons.Remove(seasonToRemove);
|
||||
}
|
||||
}
|
||||
return series;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -266,7 +313,15 @@ namespace Ombi.Api
|
|||
Log.Error(exception, "Exception when calling GetSeries by ID for Sonarr, Retrying {0}",
|
||||
timespan));
|
||||
|
||||
return policy.Execute(() => Api.ExecuteJson<Series>(request, baseUrl));
|
||||
var series = policy.Execute(() => Api.ExecuteJson<Series>(request, baseUrl));
|
||||
|
||||
// Remove the specials season
|
||||
var toRemove = series.seasons.FirstOrDefault(x => x.seasonNumber == 0);
|
||||
if (toRemove != null)
|
||||
{
|
||||
series.seasons.Remove(toRemove);
|
||||
}
|
||||
return series;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace Ombi.Core.Migration.Migrations
|
|||
content.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.UtcNow,
|
||||
ProviderId = ep.ProviderId
|
||||
ProviderId = ep.RatingKey
|
||||
});
|
||||
}
|
||||
|
||||
|
|
134
Ombi.Core.Migration/Migrations/Version2210.cs
Normal file
134
Ombi.Core.Migration/Migrations/Version2210.cs
Normal file
|
@ -0,0 +1,134 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: Version1100.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using NLog;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Store;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Models.Emby;
|
||||
using Ombi.Store.Models.Plex;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz.Collection;
|
||||
|
||||
namespace Ombi.Core.Migration.Migrations
|
||||
{
|
||||
[Migration(22100, "v2.21.0.0")]
|
||||
public class Version2210 : BaseMigration, IMigration
|
||||
{
|
||||
public Version2210(IRepository<RecentlyAddedLog> log,
|
||||
IRepository<PlexContent> content, IRepository<PlexEpisodes> plexEp, IRepository<EmbyContent> embyContent, IRepository<EmbyEpisodes> embyEp)
|
||||
{
|
||||
Log = log;
|
||||
PlexContent = content;
|
||||
PlexEpisodes = plexEp;
|
||||
EmbyContent = embyContent;
|
||||
EmbyEpisodes = embyEp;
|
||||
}
|
||||
|
||||
public int Version => 22100;
|
||||
private IRepository<RecentlyAddedLog> Log { get; }
|
||||
private IRepository<PlexContent> PlexContent { get; }
|
||||
private IRepository<PlexEpisodes> PlexEpisodes { get; }
|
||||
private IRepository<EmbyContent> EmbyContent { get; }
|
||||
private IRepository<EmbyEpisodes> EmbyEpisodes { get; }
|
||||
|
||||
public void Start(IDbConnection con)
|
||||
{
|
||||
UpdateRecentlyAdded(con);
|
||||
UpdateSchema(con, Version);
|
||||
|
||||
}
|
||||
|
||||
private void UpdateRecentlyAdded(IDbConnection con)
|
||||
{
|
||||
|
||||
//Delete the recently added table, lets start again
|
||||
Log.DeleteAll("RecentlyAddedLog");
|
||||
|
||||
|
||||
|
||||
// Plex
|
||||
var plexAllContent = PlexContent.GetAll();
|
||||
var content = new HashSet<RecentlyAddedLog>();
|
||||
foreach (var plexContent in plexAllContent)
|
||||
{
|
||||
if(plexContent.Type == PlexMediaType.Artist) continue;
|
||||
content.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.UtcNow,
|
||||
ProviderId = plexContent.ProviderId
|
||||
});
|
||||
}
|
||||
Log.BatchInsert(content, "RecentlyAddedLog");
|
||||
|
||||
var plexEpisodeses = PlexEpisodes.GetAll();
|
||||
content.Clear();
|
||||
foreach (var ep in plexEpisodeses)
|
||||
{
|
||||
content.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.UtcNow,
|
||||
ProviderId = ep.RatingKey
|
||||
});
|
||||
}
|
||||
Log.BatchInsert(content, "RecentlyAddedLog");
|
||||
|
||||
// Emby
|
||||
content.Clear();
|
||||
var embyContent = EmbyContent.GetAll();
|
||||
foreach (var plexContent in embyContent)
|
||||
{
|
||||
content.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.UtcNow,
|
||||
ProviderId = plexContent.EmbyId
|
||||
});
|
||||
}
|
||||
Log.BatchInsert(content, "RecentlyAddedLog");
|
||||
|
||||
var embyEpisodes = EmbyEpisodes.GetAll();
|
||||
content.Clear();
|
||||
foreach (var ep in embyEpisodes)
|
||||
{
|
||||
content.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.UtcNow,
|
||||
ProviderId = ep.EmbyId
|
||||
});
|
||||
}
|
||||
Log.BatchInsert(content, "RecentlyAddedLog");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@
|
|||
<Compile Include="MigrationAttribute.cs" />
|
||||
<Compile Include="MigrationRunner.cs" />
|
||||
<Compile Include="Migrations\BaseMigration.cs" />
|
||||
<Compile Include="Migrations\Version2210.cs" />
|
||||
<Compile Include="Migrations\Version2200.cs" />
|
||||
<Compile Include="Migrations\Version1100.cs" />
|
||||
<Compile Include="Migrations\Version195.cs" />
|
||||
|
|
|
@ -155,8 +155,9 @@
|
|||
<Compile Include="StatusChecker\AppveyorArtifactResult.cs" />
|
||||
<Compile Include="StatusChecker\StatusChecker.cs" />
|
||||
<Compile Include="StatusChecker\AppveyorBranchResult.cs" />
|
||||
<Compile Include="TvSender.cs" />
|
||||
<Compile Include="TvSenderOld.cs" />
|
||||
<Compile Include="Tv\TvSender.cs" />
|
||||
<Compile Include="Tv\TvSenderOld.cs" />
|
||||
<Compile Include="Tv\TvSenderV2.cs" />
|
||||
<Compile Include="Users\IUserHelper.cs" />
|
||||
<Compile Include="Users\UserHelper.cs" />
|
||||
<Compile Include="UserIdentity.cs" />
|
||||
|
|
|
@ -87,6 +87,8 @@ namespace Ombi.Core
|
|||
|
||||
var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.FullRootPath : await GetRootPath(model.RootFolderSelected, sonarrSettings);
|
||||
|
||||
|
||||
|
||||
if (episodeRequest)
|
||||
{
|
||||
// Does series exist?
|
302
Ombi.Core/Tv/TvSenderV2.cs
Normal file
302
Ombi.Core/Tv/TvSenderV2.cs
Normal file
|
@ -0,0 +1,302 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: TvSenderV2.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.SickRage;
|
||||
using Ombi.Api.Models.Sonarr;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store;
|
||||
|
||||
namespace Ombi.Core.Tv
|
||||
{
|
||||
public class TvSenderV2
|
||||
{
|
||||
public TvSenderV2(ISonarrApi sonarrApi, ISickRageApi srApi, ICacheProvider cache)
|
||||
{
|
||||
SonarrApi = sonarrApi;
|
||||
SickrageApi = srApi;
|
||||
Cache = cache;
|
||||
}
|
||||
private ISonarrApi SonarrApi { get; }
|
||||
private ISickRageApi SickrageApi { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private static Logger _log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
|
||||
public async Task<SonarrAddSeries> SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model)
|
||||
{
|
||||
return await SendToSonarr(sonarrSettings, model, string.Empty);
|
||||
}
|
||||
|
||||
|
||||
public async Task<SonarrAddSeries> SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model,
|
||||
string qualityId)
|
||||
{
|
||||
var qualityProfile = 0;
|
||||
if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality
|
||||
{
|
||||
int.TryParse(qualityId, out qualityProfile);
|
||||
}
|
||||
|
||||
if (qualityProfile <= 0)
|
||||
{
|
||||
int.TryParse(sonarrSettings.QualityProfile, out qualityProfile);
|
||||
}
|
||||
var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.FullRootPath : await GetSonarrRootPath(model.RootFolderSelected, sonarrSettings);
|
||||
|
||||
var episodeRequest = model.Episodes.Any();
|
||||
var requestAll = model.SeasonsRequested?.Equals("All", StringComparison.CurrentCultureIgnoreCase);
|
||||
var first = model.SeasonsRequested?.Equals("First", StringComparison.CurrentCultureIgnoreCase);
|
||||
var latest = model.SeasonsRequested?.Equals("Latest", StringComparison.CurrentCultureIgnoreCase);
|
||||
var specificSeasonRequest = model.SeasonList?.Any();
|
||||
|
||||
if (episodeRequest)
|
||||
{
|
||||
return await ProcessSonarrEpisodeRequest(sonarrSettings, model, qualityProfile, rootFolderPath);
|
||||
}
|
||||
|
||||
if (requestAll ?? false)
|
||||
{
|
||||
return await ProcessSonarrRequestSeason(sonarrSettings, model, qualityProfile, rootFolderPath);
|
||||
}
|
||||
|
||||
if (first ?? false)
|
||||
{
|
||||
return await ProcessSonarrRequestSeason(sonarrSettings, model, qualityProfile, rootFolderPath);
|
||||
}
|
||||
|
||||
if (latest ?? false)
|
||||
{
|
||||
return await ProcessSonarrRequestSeason(sonarrSettings, model, qualityProfile, rootFolderPath);
|
||||
}
|
||||
|
||||
if (specificSeasonRequest ?? false)
|
||||
{
|
||||
return await ProcessSonarrRequestSeason(sonarrSettings, model, qualityProfile, rootFolderPath);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task<SonarrAddSeries> ProcessSonarrRequestSeason(SonarrSettings sonarrSettings, RequestedModel model, int qualityId, string rootFolderPath)
|
||||
{
|
||||
// Does the series exist?
|
||||
var series = await GetSonarrSeries(sonarrSettings, model.ProviderId);
|
||||
if (series == null)
|
||||
{
|
||||
//WORKS
|
||||
// Add the series
|
||||
return AddSeries(sonarrSettings, model, rootFolderPath, qualityId);
|
||||
}
|
||||
|
||||
// Also make sure the series is now monitored otherwise we won't search for it
|
||||
series.monitored = true;
|
||||
foreach (var seasons in series.seasons)
|
||||
{
|
||||
seasons.monitored = true;
|
||||
}
|
||||
|
||||
// Send the update command
|
||||
series = SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri);
|
||||
SonarrApi.SearchForSeries(series.id, sonarrSettings.ApiKey, sonarrSettings.FullUri);
|
||||
return new SonarrAddSeries { title = series.title };
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task<SonarrAddSeries> ProcessSonarrEpisodeRequest(SonarrSettings sonarrSettings, RequestedModel model, int qualityId, string rootFolderPath)
|
||||
{
|
||||
// Does the series exist?
|
||||
|
||||
var series = await GetSonarrSeries(sonarrSettings, model.ProviderId);
|
||||
if (series == null)
|
||||
{
|
||||
var seriesToAdd = new SonarrAddSeries
|
||||
{
|
||||
seasonFolder = sonarrSettings.SeasonFolders,
|
||||
title = model.Title,
|
||||
qualityProfileId = qualityId,
|
||||
tvdbId = model.ProviderId,
|
||||
titleSlug = model.Title,
|
||||
seasons = new List<Season>(),
|
||||
rootFolderPath = rootFolderPath,
|
||||
monitored = true, // Montior the series
|
||||
images = new List<SonarrImage>(),
|
||||
addOptions = new AddOptions
|
||||
{
|
||||
ignoreEpisodesWithFiles = true, // We don't really care about these
|
||||
ignoreEpisodesWithoutFiles = true, // We do not want to grab random episodes missing
|
||||
searchForMissingEpisodes = false // we want don't want to search for the missing episodes either
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 1; i <= model.SeasonCount; i++)
|
||||
{
|
||||
var season = new Season
|
||||
{
|
||||
seasonNumber = i,
|
||||
monitored = false // Do not monitor any seasons
|
||||
};
|
||||
seriesToAdd.seasons.Add(season);
|
||||
}
|
||||
|
||||
// Add the series now
|
||||
var result = SonarrApi.AddSeries(seriesToAdd, sonarrSettings.ApiKey, sonarrSettings.FullUri);
|
||||
|
||||
await RequestEpisodesForSonarr(model, result.id, sonarrSettings);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
await RequestEpisodesForSonarr(model, series.id, sonarrSettings);
|
||||
}
|
||||
|
||||
return new SonarrAddSeries() { title = model.Title };
|
||||
}
|
||||
|
||||
public SonarrAddSeries AddSeries(SonarrSettings sonarrSettings, RequestedModel model, string rootFolderPath, int qualityId)
|
||||
{
|
||||
//WORKS
|
||||
// Add the series
|
||||
var seriesToAdd = new SonarrAddSeries
|
||||
{
|
||||
seasonFolder = sonarrSettings.SeasonFolders,
|
||||
title = model.Title,
|
||||
qualityProfileId = qualityId,
|
||||
tvdbId = model.ProviderId,
|
||||
titleSlug = model.Title,
|
||||
seasons = new List<Season>(),
|
||||
rootFolderPath = rootFolderPath,
|
||||
monitored = true, // Montior the series
|
||||
images = new List<SonarrImage>(),
|
||||
addOptions = new AddOptions
|
||||
{
|
||||
ignoreEpisodesWithFiles = true, // We don't really care about these
|
||||
ignoreEpisodesWithoutFiles = false, // We want to get the whole season
|
||||
searchForMissingEpisodes = true // we want to search for missing
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 1; i <= model.SeasonCount; i++)
|
||||
{
|
||||
var season = new Season
|
||||
{
|
||||
seasonNumber = i,
|
||||
// The model.SeasonList.Lenth is 0 when this is a "request all"
|
||||
monitored = model.SeasonList.Length == 0 || model.SeasonList.Any(x => x == i)
|
||||
};
|
||||
seriesToAdd.seasons.Add(season);
|
||||
}
|
||||
|
||||
return SonarrApi.AddSeries(seriesToAdd, sonarrSettings.ApiKey, sonarrSettings.FullUri);
|
||||
}
|
||||
|
||||
private async Task RequestEpisodesForSonarr(RequestedModel model, int showId, SonarrSettings sonarrSettings)
|
||||
{
|
||||
// Now lookup all episodes
|
||||
var ep = SonarrApi.GetEpisodes(showId.ToString(), sonarrSettings.ApiKey, sonarrSettings.FullUri);
|
||||
var episodes = ep?.ToList() ?? new List<SonarrEpisodes>();
|
||||
|
||||
var internalEpisodeIds = new List<int>();
|
||||
var tasks = new List<Task>();
|
||||
foreach (var r in model.Episodes)
|
||||
{
|
||||
// Match the episode and season number.
|
||||
// If the episode is monitored we might not be searching for it.
|
||||
var episode =
|
||||
episodes.FirstOrDefault(
|
||||
x => x.episodeNumber == r.EpisodeNumber && x.seasonNumber == r.SeasonNumber);
|
||||
if (episode == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var episodeInfo = SonarrApi.GetEpisode(episode.id.ToString(), sonarrSettings.ApiKey,
|
||||
sonarrSettings.FullUri);
|
||||
episodeInfo.monitored = true; // Set the episode to monitored
|
||||
tasks.Add(Task.Run(() => SonarrApi.UpdateEpisode(episodeInfo, sonarrSettings.ApiKey,
|
||||
sonarrSettings.FullUri)));
|
||||
internalEpisodeIds.Add(episode.id);
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks.ToArray());
|
||||
|
||||
SonarrApi.SearchForEpisodes(internalEpisodeIds.ToArray(), sonarrSettings.ApiKey, sonarrSettings.FullUri);
|
||||
}
|
||||
|
||||
public SickRageTvAdd SendToSickRage(SickRageSettings sickRageSettings, RequestedModel model)
|
||||
{
|
||||
return SendToSickRage(sickRageSettings, model, sickRageSettings.QualityProfile);
|
||||
}
|
||||
|
||||
public SickRageTvAdd SendToSickRage(SickRageSettings sickRageSettings, RequestedModel model, string qualityId)
|
||||
{
|
||||
_log.Info("Sending to SickRage {0}", model.Title);
|
||||
if (sickRageSettings.Qualities.All(x => x.Key != qualityId))
|
||||
{
|
||||
qualityId = sickRageSettings.QualityProfile;
|
||||
}
|
||||
|
||||
var apiResult = SickrageApi.AddSeries(model.ProviderId, model.SeasonCount, model.SeasonList, qualityId,
|
||||
sickRageSettings.ApiKey, sickRageSettings.FullUri);
|
||||
|
||||
var result = apiResult.Result;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Series> GetSonarrSeries(SonarrSettings sonarrSettings, int showId)
|
||||
{
|
||||
var task = await Task.Run(() => SonarrApi.GetSeries(sonarrSettings.ApiKey, sonarrSettings.FullUri)).ConfigureAwait(false);
|
||||
var selectedSeries = task.FirstOrDefault(series => series.tvdbId == showId);
|
||||
|
||||
return selectedSeries;
|
||||
}
|
||||
|
||||
private async Task<string> GetSonarrRootPath(int pathId, SonarrSettings sonarrSettings)
|
||||
{
|
||||
var rootFoldersResult = await Cache.GetOrSetAsync(CacheKeys.SonarrRootFolders, async () =>
|
||||
{
|
||||
return await Task.Run(() => SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri));
|
||||
});
|
||||
|
||||
foreach (var r in rootFoldersResult.Where(r => r.id == pathId))
|
||||
{
|
||||
return r.path;
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -276,7 +276,8 @@ namespace Ombi.Services.Jobs
|
|||
Title = m.Title,
|
||||
Type = Store.Models.Plex.PlexMediaType.Movie,
|
||||
Url = m.Url,
|
||||
ItemId = m.ItemId
|
||||
ItemId = m.ItemId,
|
||||
AddedAt = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -318,7 +319,8 @@ namespace Ombi.Services.Jobs
|
|||
Type = Store.Models.Plex.PlexMediaType.Show,
|
||||
Url = t.Url,
|
||||
Seasons = ByteConverterHelper.ReturnBytes(t.Seasons),
|
||||
ItemId = t.ItemId
|
||||
ItemId = t.ItemId,
|
||||
AddedAt = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -360,7 +362,8 @@ namespace Ombi.Services.Jobs
|
|||
Title = a.Title,
|
||||
Type = Store.Models.Plex.PlexMediaType.Artist,
|
||||
Url = a.Url,
|
||||
ItemId = "album"
|
||||
ItemId = "album",
|
||||
AddedAt = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ namespace Ombi.Services.Jobs
|
|||
var metadata = PlexApi.GetEpisodeMetaData(settings.PlexAuthToken, settings.FullUri, video.RatingKey);
|
||||
|
||||
// Loop through the metadata and create the model to insert into the DB
|
||||
foreach (var metadataVideo in metadata.Video)
|
||||
foreach (var metadataVideo in metadata?.Video ?? new List<Video>())
|
||||
{
|
||||
if(string.IsNullOrEmpty(metadataVideo.GrandparentTitle))
|
||||
{
|
||||
|
@ -119,11 +119,11 @@ namespace Ombi.Services.Jobs
|
|||
entities.TryAdd(
|
||||
new PlexEpisodes
|
||||
{
|
||||
EpisodeNumber = epInfo.EpisodeNumber,
|
||||
EpisodeNumber = epInfo?.EpisodeNumber ?? 0,
|
||||
EpisodeTitle = metadataVideo.Title,
|
||||
ProviderId = epInfo.ProviderId,
|
||||
ProviderId = epInfo?.ProviderId ?? "",
|
||||
RatingKey = metadataVideo.RatingKey,
|
||||
SeasonNumber = epInfo.SeasonNumber,
|
||||
SeasonNumber = epInfo?.SeasonNumber ?? 0,
|
||||
ShowTitle = metadataVideo.GrandparentTitle
|
||||
},
|
||||
1);
|
||||
|
@ -152,15 +152,7 @@ namespace Ombi.Services.Jobs
|
|||
return;
|
||||
}
|
||||
|
||||
var jobs = Job.GetJobs();
|
||||
var job = jobs.FirstOrDefault(x => x.Name.Equals(JobNames.EpisodeCacher, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (job != null)
|
||||
{
|
||||
if (job.LastRun > DateTime.Now.AddHours(-11)) // If it's been run in the last 11 hours
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Job.SetRunning(true, JobNames.EpisodeCacher);
|
||||
CacheEpisodes(s);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ using Ombi.Store.Models.Emby;
|
|||
using Ombi.Store.Repository;
|
||||
using TMDbLib.Objects.Exceptions;
|
||||
using EmbyMediaType = Ombi.Store.Models.Plex.EmbyMediaType;
|
||||
using Polly;
|
||||
|
||||
namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
||||
{
|
||||
|
@ -114,21 +115,27 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
|
||||
var firstRun = !recentlyAdded.Any();
|
||||
|
||||
var filteredMovies = movie.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList();
|
||||
var filteredEp = episodes.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList();
|
||||
var filteredSeries = series.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList();
|
||||
var filteredMovies = movie.Where(m => recentlyAdded.All(x => x.ProviderId != m.EmbyId)).ToList();
|
||||
var filteredEp = episodes.Where(m => recentlyAdded.All(x => x.ProviderId != m.EmbyId)).ToList();
|
||||
var filteredSeries = series.Where(m => recentlyAdded.All(x => x.ProviderId != m.EmbyId)).ToList();
|
||||
|
||||
var info = new List<EmbyRecentlyAddedModel>();
|
||||
foreach (var m in filteredMovies)
|
||||
foreach (var m in filteredMovies.OrderByDescending(x => x.AddedAt))
|
||||
{
|
||||
|
||||
var i = Api.GetInformation(m.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Movie,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
info.Add(new EmbyRecentlyAddedModel
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) =>
|
||||
Log.Error(exception, "Exception thrown when processing an emby movie for the newsletter, Retrying {0}", timespan));
|
||||
var result = policy.Execute(() =>
|
||||
{
|
||||
EmbyInformation = i,
|
||||
EmbyContent = m
|
||||
var i = Api.GetInformation(m.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Movie,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
|
||||
return new EmbyRecentlyAddedModel
|
||||
{
|
||||
EmbyInformation = i,
|
||||
EmbyContent = m
|
||||
};
|
||||
});
|
||||
info.Add(result);
|
||||
}
|
||||
GenerateMovieHtml(info, sb);
|
||||
newsletter.MovieCount = info.Count;
|
||||
|
@ -137,51 +144,59 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
|
||||
// Check if there are any epiosdes, then get the series info.
|
||||
// Otherwise then just add the series to the newsletter
|
||||
if (test && !filteredEp.Any() && episodes.Any())
|
||||
{
|
||||
// if this is a test make sure we show something
|
||||
filteredEp = episodes.Take(5).ToList();
|
||||
}
|
||||
if (filteredEp.Any())
|
||||
{
|
||||
var recentlyAddedModel = new List<EmbyRecentlyAddedModel>();
|
||||
foreach (var embyEpisodes in filteredEp)
|
||||
{
|
||||
// Let's sleep, Emby can't keep up with us.
|
||||
Thread.Sleep(1000);
|
||||
try
|
||||
{
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) =>
|
||||
Log.Error(exception, "Exception thrown when processing an emby episode for the newsletter, Retrying {0}", timespan));
|
||||
|
||||
// Find related series item
|
||||
var relatedSeries = series.FirstOrDefault(x => x.EmbyId == embyEpisodes.ParentId);
|
||||
|
||||
if (relatedSeries == null)
|
||||
policy.Execute(() =>
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Find related series item
|
||||
var relatedSeries = series.FirstOrDefault(x => x.EmbyId == embyEpisodes.ParentId);
|
||||
|
||||
// Get series information
|
||||
var i = Api.GetInformation(relatedSeries.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Series,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
|
||||
Thread.Sleep(200);
|
||||
var episodeInfo = Api.GetInformation(embyEpisodes.EmbyId,
|
||||
Ombi.Api.Models.Emby.EmbyMediaType.Episode,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
|
||||
// Check if we already have this series
|
||||
var existingSeries = recentlyAddedModel.FirstOrDefault(x =>
|
||||
x.EmbyInformation.SeriesInformation.Id.Equals(i.SeriesInformation.Id,
|
||||
StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
if (existingSeries != null)
|
||||
{
|
||||
existingSeries.EpisodeInformation.Add(episodeInfo.EpisodeInformation);
|
||||
}
|
||||
else
|
||||
{
|
||||
recentlyAddedModel.Add(new EmbyRecentlyAddedModel
|
||||
if (relatedSeries == null)
|
||||
{
|
||||
EmbyInformation = i,
|
||||
EpisodeInformation = new List<EmbyEpisodeInformation>() { episodeInfo.EpisodeInformation },
|
||||
EmbyContent = relatedSeries
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get series information
|
||||
var i = Api.GetInformation(relatedSeries.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Series,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
|
||||
Thread.Sleep(200);
|
||||
var episodeInfo = Api.GetInformation(embyEpisodes.EmbyId,
|
||||
Ombi.Api.Models.Emby.EmbyMediaType.Episode,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
|
||||
// Check if we already have this series
|
||||
var existingSeries = recentlyAddedModel.FirstOrDefault(x =>
|
||||
x.EmbyInformation.SeriesInformation.Id.Equals(i.SeriesInformation.Id,
|
||||
StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
if (existingSeries != null)
|
||||
{
|
||||
existingSeries.EpisodeInformation.Add(episodeInfo.EpisodeInformation);
|
||||
}
|
||||
else
|
||||
{
|
||||
recentlyAddedModel.Add(new EmbyRecentlyAddedModel
|
||||
{
|
||||
EmbyInformation = i,
|
||||
EpisodeInformation = new List<EmbyEpisodeInformation>() { episodeInfo.EpisodeInformation },
|
||||
EmbyContent = relatedSeries
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (JsonReaderException)
|
||||
|
@ -195,15 +210,23 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
}
|
||||
else
|
||||
{
|
||||
foreach (var t in filteredSeries)
|
||||
foreach (var t in filteredSeries.OrderByDescending(x => x.AddedAt))
|
||||
{
|
||||
var i = Api.GetInformation(t.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Series,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
var item = new EmbyRecentlyAddedModel
|
||||
|
||||
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) =>
|
||||
Log.Error(exception, "Exception thrown when processing an emby series for the newsletter, Retrying {0}", timespan));
|
||||
var item = policy.Execute(() =>
|
||||
{
|
||||
EmbyContent = t,
|
||||
EmbyInformation = i,
|
||||
};
|
||||
var i = Api.GetInformation(t.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Series,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
var model = new EmbyRecentlyAddedModel
|
||||
{
|
||||
EmbyContent = t,
|
||||
EmbyInformation = i,
|
||||
};
|
||||
return model;
|
||||
});
|
||||
info.Add(item);
|
||||
}
|
||||
}
|
||||
|
@ -221,7 +244,7 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = a.ProviderId,
|
||||
ProviderId = a.EmbyId,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
|
@ -229,7 +252,15 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = a.ProviderId,
|
||||
ProviderId = a.EmbyId,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
foreach (var s in filteredSeries)
|
||||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = s.EmbyId,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
|
|
|
@ -117,11 +117,17 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
var firstRun = !recentlyAdded.Any();
|
||||
|
||||
var filteredMovies = movie.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList();
|
||||
var filteredEp = episodes.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList();
|
||||
var filteredEp = episodes.Where(m => recentlyAdded.All(x => x.ProviderId != m.RatingKey)).ToList();
|
||||
var filteredSeries = series.Where(x => recentlyAdded.All(c => c.ProviderId != x.ProviderId)).ToList();
|
||||
|
||||
var info = new List<PlexRecentlyAddedModel>();
|
||||
foreach (var m in filteredMovies)
|
||||
|
||||
if (test && !filteredMovies.Any())
|
||||
{
|
||||
// if this is a test make sure we show something
|
||||
filteredMovies = movie.Take(5).ToList();
|
||||
}
|
||||
foreach (var m in filteredMovies.OrderByDescending(x => x.AddedAt))
|
||||
{
|
||||
var i = Api.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri, m.ItemId);
|
||||
if (i.Video == null)
|
||||
|
@ -138,6 +144,11 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
newsletter.MovieCount = info.Count;
|
||||
|
||||
info.Clear();
|
||||
if (test && !filteredEp.Any() && episodes.Any())
|
||||
{
|
||||
// if this is a test make sure we show something
|
||||
filteredEp = episodes.Take(5).ToList();
|
||||
}
|
||||
if (filteredEp.Any())
|
||||
{
|
||||
var recentlyAddedModel = new List<PlexRecentlyAddedModel>();
|
||||
|
@ -178,7 +189,12 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
}
|
||||
else
|
||||
{
|
||||
foreach (var t in filteredSeries)
|
||||
if (test && !filteredSeries.Any())
|
||||
{
|
||||
// if this is a test make sure we show something
|
||||
filteredSeries = series.Take(5).ToList();
|
||||
}
|
||||
foreach (var t in filteredSeries.OrderByDescending(x => x.AddedAt))
|
||||
{
|
||||
var i = Api.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri, t.ItemId);
|
||||
if (i.Directory == null)
|
||||
|
@ -215,7 +231,7 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = a.ProviderId,
|
||||
ProviderId = a.RatingKey,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
|
@ -324,7 +340,7 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
|
||||
try
|
||||
{
|
||||
var info = TvApi.ShowLookupByTheTvDbId(int.Parse(PlexHelper.GetProviderIdFromPlexGuid(t.Metadata.Directory.Guid)));
|
||||
var info = TvApi.ShowLookupByTheTvDbId(int.Parse(PlexHelper.GetProviderIdFromPlexGuid(t?.Metadata?.Directory?.Guid ?? string.Empty)));
|
||||
|
||||
var banner = info.image?.original;
|
||||
if (!string.IsNullOrEmpty(banner))
|
||||
|
@ -359,7 +375,7 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
|||
for (var i = 0; i < orderedEpisodes.Count; i++)
|
||||
{
|
||||
var ep = orderedEpisodes[i];
|
||||
if (i <= orderedEpisodes.Count - 1)
|
||||
if (i < orderedEpisodes.Count - 1)
|
||||
{
|
||||
epSb.Append($"{ep.Video.FirstOrDefault().Index},");
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Polly, Version=4.3.0.0, Culture=neutral, PublicKeyToken=c8a3ffc3f8f825cc" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Security" />
|
||||
|
|
|
@ -34,6 +34,9 @@ namespace Ombi.Store.Models
|
|||
[Table("RecentlyAddedLog")]
|
||||
public class RecentlyAddedLog : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// This is actually a unique id for that content...
|
||||
/// </summary>
|
||||
public string ProviderId { get; set; }
|
||||
public DateTime AddedAt { get; set; }
|
||||
}
|
|
@ -68,7 +68,7 @@
|
|||
<Compile Include="Models\Emby\EmbyContent.cs" />
|
||||
<Compile Include="Models\Emby\EmbyEpisodes.cs" />
|
||||
<Compile Include="Models\IssueBlobs.cs" />
|
||||
<Compile Include="Models\RecenetlyAddedLog.cs" />
|
||||
<Compile Include="Models\RecentlyAddedLog.cs" />
|
||||
<Compile Include="Models\Plex\PlexEpisodes.cs" />
|
||||
<Compile Include="Models\Emby\EmbyUsers.cs" />
|
||||
<Compile Include="Models\Plex\PlexUsers.cs" />
|
||||
|
|
|
@ -142,8 +142,8 @@ namespace Ombi.UI
|
|||
pipelines.AfterRequest.AddItemToEndOfPipeline((ctx) =>
|
||||
{
|
||||
ctx.Response.WithHeader("Access-Control-Allow-Origin", "*")
|
||||
.WithHeader("Access-Control-Allow-Methods", "POST,GET")
|
||||
.WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type");
|
||||
.WithHeader("Access-Control-Allow-Methods", "POST,GET")
|
||||
.WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type");
|
||||
|
||||
});
|
||||
base.RequestStartup(container, pipelines, context);
|
||||
|
|
|
@ -46,6 +46,7 @@ using Ombi.Core;
|
|||
using Ombi.Core.Models;
|
||||
using Ombi.Core.Queue;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Core.Tv;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Helpers.Analytics;
|
||||
using Ombi.Helpers.Permissions;
|
||||
|
@ -1119,10 +1120,12 @@ namespace Ombi.UI.Modules
|
|||
RequestedUsers = new List<string> { Username },
|
||||
Issues = IssueState.None,
|
||||
ImdbId = showInfo.externals?.imdb ?? string.Empty,
|
||||
SeasonCount = showInfo.Season.Count,
|
||||
TvDbId = showId.ToString()
|
||||
TvDbId = showId.ToString(),
|
||||
ProviderId = showId
|
||||
};
|
||||
|
||||
var totalSeasons = showInfo.Season.GroupBy(x => x.SeasonNumber);
|
||||
model.SeasonCount = totalSeasons.Count();
|
||||
var seasonsList = new List<int>();
|
||||
switch (seasons)
|
||||
{
|
||||
|
@ -1884,7 +1887,8 @@ namespace Ombi.UI.Modules
|
|||
{
|
||||
model.Approved = true;
|
||||
var s = await sonarrSettings;
|
||||
var sender = new TvSenderOld(SonarrApi, SickrageApi, Cache); // TODO put back
|
||||
var sender = new TvSenderV2(SonarrApi, SickrageApi, Cache);
|
||||
//var sender = new TvSenderOld(SonarrApi, SickrageApi, Cache);
|
||||
if (s.Enabled)
|
||||
{
|
||||
var result = await sender.SendToSonarr(s, model);
|
||||
|
|
|
@ -78,6 +78,14 @@
|
|||
<a href="https://github.com/tidusjar/Ombi" target="_blank">https://github.com/tidusjar/Ombi</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Forums
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://forums.ombi.io/" target="_blank">https://forums.ombi.io/</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Wiki
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<div class="form-group">
|
||||
<div>
|
||||
|
||||
<button id="recentlyAddedBtn" class="btn btn-primary-outline">Send test email to Admin @Html.ToolTip("Note: nothing will send if there is no new content...")
|
||||
<button id="recentlyAddedBtn" class="btn btn-primary-outline">Send test email to Admin @Html.ToolTip("Note: If there is nothing new when testing this, we will just grab some random titles. If there are new items, then we will show those new items. Testing will not mark the content as 'Previously Sent'")
|
||||
<div id="testEmailSpinner"></div></button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,6 +16,10 @@ ___
|
|||
|----------|:---------------------------:|:----------------------------:|:----------------------------:|
|
||||
| AppVeyor | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/master) | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/eap) | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/dev)
|
||||
| Download |[](https://github.com/tidusjar/Ombi/releases) | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/eap/artifacts) | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/dev/artifacts) |
|
||||
|
||||
We now have a forums!
|
||||
Check it out: [https://forums.ombi.io/](https://forums.ombi.io)
|
||||
|
||||
# Features
|
||||
Here some of the features Ombi has:
|
||||
* All your users to Request Movies, TV Shows (Whole series, whole seasons or even single episodes!) and Albums
|
||||
|
|
|
@ -3,9 +3,9 @@ configuration: Release
|
|||
assembly_info:
|
||||
patch: true
|
||||
file: '**\AssemblyInfo.*'
|
||||
assembly_version: '2.2.0'
|
||||
assembly_version: '2.2.1'
|
||||
assembly_file_version: '{version}'
|
||||
assembly_informational_version: '2.2.0'
|
||||
assembly_informational_version: '2.2.1'
|
||||
before_build:
|
||||
- cmd: appveyor-retry nuget restore
|
||||
build:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue