Merge pull request #1011 from tidusjar/dev

Dev
pull/1028/head
Jamie 8 years ago committed by GitHub
commit 129269c9b5

@ -0,0 +1,104 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: TmdbMovieDetails.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.Collections.Generic;
namespace Ombi.Api.Models.Movie
{
public class Genre
{
public int id { get; set; }
public string name { get; set; }
}
public class ProductionCompany
{
public string name { get; set; }
public int id { get; set; }
}
public class ProductionCountry
{
public string iso_3166_1 { get; set; }
public string name { get; set; }
}
public class SpokenLanguage
{
public string iso_639_1 { get; set; }
public string name { get; set; }
}
public class Result
{
public string id { get; set; }
public string iso_639_1 { get; set; }
public string iso_3166_1 { get; set; }
public string key { get; set; }
public string name { get; set; }
public string site { get; set; }
public int size { get; set; }
public string type { get; set; }
}
public class Videos
{
public List<Result> results { get; set; }
}
public class TmdbMovieDetails
{
public bool adult { get; set; }
public string backdrop_path { get; set; }
public object belongs_to_collection { get; set; }
public int budget { get; set; }
public List<Genre> genres { get; set; }
public string homepage { get; set; }
public int id { get; set; }
public string imdb_id { get; set; }
public string original_language { get; set; }
public string original_title { get; set; }
public string overview { get; set; }
public double popularity { get; set; }
public string poster_path { get; set; }
public List<ProductionCompany> production_companies { get; set; }
public List<ProductionCountry> production_countries { get; set; }
public string release_date { get; set; }
public int revenue { get; set; }
public int runtime { get; set; }
public List<SpokenLanguage> spoken_languages { get; set; }
public string status { get; set; }
public string tagline { get; set; }
public string title { get; set; }
public bool video { get; set; }
public double vote_average { get; set; }
public int vote_count { get; set; }
public Videos videos { get; set; }
}
}

@ -54,6 +54,7 @@
<Compile Include="Movie\CouchPotatoProfiles.cs" />
<Compile Include="Movie\CouchPotatoStatus.cs" />
<Compile Include="Movie\CouchPotatoApiKey.cs" />
<Compile Include="Movie\TmdbMovieDetails.cs" />
<Compile Include="Music\HeadphonesAlbumSearchResult.cs" />
<Compile Include="Music\HeadphonesArtistSearchResult.cs" />
<Compile Include="Music\HeadphonesGetIndex.cs" />

@ -47,7 +47,7 @@ namespace Ombi.Api.Models.Radarr
{
public string title { get; set; }
public string sortTitle { get; set; }
public int sizeOnDisk { get; set; }
public double sizeOnDisk { get; set; }
public string status { get; set; }
public string overview { get; set; }
public string inCinemas { get; set; }

@ -32,6 +32,8 @@ namespace Ombi.Api
public abstract class MovieBase
{
private static readonly string Encrypted = "0T3QNSseexLO7n7UPiJvl70Y+KKnvbeTlsusl7Kwq0hPH0BHOuFNGwksNCjkwqWedyDdI/MJeUR4wtL4bIl0Z+//uHXEaYM/4H2pjeLbH5EWdUe5TTj1AhaIR5PQweamvcienRyFD/3YPCC/+qL5mHkKXBkPumMod3Zb/4yN0Ik=";
protected string ApiKey = StringCipher.Decrypt(Encrypted, "ApiKey");
private string _apiKey;
protected string ApiKey => _apiKey ?? (_apiKey = StringCipher.Decrypt(Encrypted, "ApiKey"));
}
}

@ -25,12 +25,18 @@
// ************************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NLog;
using NLog.Fluent;
using Ombi.Api.Models.Movie;
using RestSharp;
using TMDbLib.Client;
using TMDbLib.Objects.General;
using TMDbLib.Objects.Movies;
using TMDbLib.Objects.Search;
using Movie = TMDbLib.Objects.Movies.Movie;
namespace Ombi.Api
{
@ -39,9 +45,13 @@ namespace Ombi.Api
public TheMovieDbApi()
{
Client = new TMDbClient(ApiKey);
Api = new ApiRequest();
}
private ApiRequest Api { get; }
public TMDbClient Client { get; set; }
private const string BaseUrl = "https://api.themoviedb.org/3/";
private static Logger Log = LogManager.GetCurrentClassLogger();
public async Task<List<SearchMovie>> SearchMovie(string searchTerm)
{
var results = await Client.SearchMovie(searchTerm);
@ -56,7 +66,27 @@ namespace Ombi.Api
public async Task<List<MovieResult>> GetUpcomingMovies()
{
var movies = await Client.GetMovieList(MovieListType.Upcoming);
return movies?.Results ?? new List<MovieResult>();
return movies?.Results ?? new List<MovieResult>();
}
public TmdbMovieDetails GetMovieInformationWithVideos(int tmdbId)
{
var request = new RestRequest { Resource = "movie/{movieId}", Method = Method.GET };
request.AddUrlSegment("movieId", tmdbId.ToString());
request.AddQueryParameter("api_key", ApiKey);
request.AddQueryParameter("append_to_response", "videos"); // Get the videos
try
{
var obj = Api.ExecuteJson<TmdbMovieDetails>(request, new Uri(BaseUrl));
return obj;
}
catch (Exception e)
{
Log.Error(e);
return null;
}
}
public async Task<Movie> GetMovieInformation(int tmdbId)

@ -0,0 +1,64 @@
#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.Data;
using NLog;
using Ombi.Core.SettingModels;
namespace Ombi.Core.Migration.Migrations
{
[Migration(22000, "v2.20.0.0")]
public class Version2200 : BaseMigration, IMigration
{
public Version2200(ISettingsService<CustomizationSettings> custom)
{
Customization = custom;
}
public int Version => 22000;
private ISettingsService<CustomizationSettings> Customization { get; set; }
private static Logger Logger = LogManager.GetCurrentClassLogger();
public void Start(IDbConnection con)
{
//UpdateCustomSettings(); Turned off the migration for now until the search has been improved on.
//UpdateSchema(con, Version);
}
private void UpdateCustomSettings()
{
var settings = Customization.GetSettings();
settings.NewSearch = true; // Use the new search
Customization.SaveSettings(settings);
}
}
}

@ -69,6 +69,7 @@
<Compile Include="MigrationAttribute.cs" />
<Compile Include="MigrationRunner.cs" />
<Compile Include="Migrations\BaseMigration.cs" />
<Compile Include="Migrations\Version2200.cs" />
<Compile Include="Migrations\Version1100.cs" />
<Compile Include="Migrations\Version195.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

@ -53,5 +53,7 @@ namespace Ombi.Core.SettingModels
public int DefaultLang { get; set; }
public bool NewSearch { get; set; }
}
}

@ -34,7 +34,6 @@ namespace Ombi.Core.SettingModels
public string EmailSender { get; set; }
public string EmailUsername { get; set; }
public bool Authentication { get; set; }
public bool EnableUserEmailNotifications { get; set; }
public string RecipientEmail { get; set; }
}
}

@ -32,6 +32,13 @@ namespace Ombi.Core.SettingModels
public string ApiKey { get; set; }
public string QualityProfile { get; set; }
public bool SeasonFolders { get; set; }
/// <summary>
/// This is the root path ID
/// </summary>
/// <value>
/// The root path.
/// </value>
public string RootPath { get; set; }
public string FullRootPath { get; set; }
}
}

@ -85,7 +85,7 @@ namespace Ombi.Core
var latest = model.SeasonsRequested?.Equals("Latest", StringComparison.CurrentCultureIgnoreCase);
var specificSeasonRequest = model.SeasonList?.Any();
var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.RootPath : await GetRootPath(model.RootFolderSelected, sonarrSettings);
var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.FullRootPath : await GetRootPath(model.RootFolderSelected, sonarrSettings);
if (episodeRequest)
{

@ -70,7 +70,7 @@ namespace Ombi.Core
{
int.TryParse(sonarrSettings.QualityProfile, out qualityProfile);
}
var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.RootPath : await GetRootPath(model.RootFolderSelected, sonarrSettings);
var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.FullRootPath : await GetRootPath(model.RootFolderSelected, sonarrSettings);
var series = await GetSonarrSeries(sonarrSettings, model.ProviderId);

@ -66,7 +66,15 @@ namespace Ombi.Services.Jobs
var movies = RadarrApi.GetMovies(settings.ApiKey, settings.FullUri);
if (movies != null)
{
var movieIds = movies.Select(x => x.tmdbId).ToList();
var movieIds = new List<int>();
foreach (var m in movies)
{
if (m.tmdbId > 0)
{
movieIds.Add(m.tmdbId);
}
}
//var movieIds = movies.Select(x => x.tmdbId).ToList();
Cache.Set(CacheKeys.RadarrMovies, movieIds, CacheKeys.TimeFrameMinutes.SchedulerCaching);
}
}

@ -119,14 +119,6 @@ namespace Ombi.Services.Notification
return false;
}
if (!settings.EnableUserEmailNotifications)
{
if (!settings.Enabled)
{
return false;
}
}
return true;
}
@ -237,10 +229,6 @@ namespace Ombi.Services.Notification
private async Task EmailAvailableRequest(NotificationModel model, EmailNotificationSettings settings)
{
if (!settings.EnableUserEmailNotifications)
{
await Task.FromResult(false);
}
var email = new EmailBasicTemplate();
var html = email.LoadTemplate(
$"Ombi: {model.Title} is now available!",

@ -154,7 +154,25 @@ namespace Ombi.Services.Notification
// Get the usernames or alias depending if they have an alias
var userNamesWithFeature = users.Select(x => x.UsernameOrAlias).ToList();
Log.Debug("Users with the feature count {0}", userNamesWithFeature.Count);
Log.Debug("Usernames: ");
foreach (var u in userNamesWithFeature)
{
Log.Debug(u);
}
Log.Debug("Users in the requested model count: {0}", model.AllUsers.Count);
Log.Debug("usernames from model: ");
foreach (var modelAllUser in model.AllUsers)
{
Log.Debug(modelAllUser);
}
if (model.AllUsers == null || !model.AllUsers.Any())
{
Log.Debug("There are no users in the model.AllUsers, no users to notify");
return;
}
var usersToNotify = userNamesWithFeature.Intersect(model.AllUsers, StringComparer.CurrentCultureIgnoreCase).ToList();
if (!usersToNotify.Any())

@ -27,9 +27,6 @@ namespace Ombi.Store
public string Status { get; set; }
public bool Approved { get; set; }
[Obsolete("Use RequestedUsers")] //TODO remove this obsolete property
public string RequestedBy { get; set; }
public DateTime RequestedDate { get; set; }
public bool Available { get; set; }
public IssueState Issues { get; set; }
@ -60,14 +57,9 @@ namespace Ombi.Store
get
{
var u = new List<string>();
if (!string.IsNullOrEmpty(RequestedBy))
{
u.Add(RequestedBy);
}
if (RequestedUsers != null && RequestedUsers.Any())
{
u.AddRange(RequestedUsers.Where(requestedUser => requestedUser != RequestedBy));
u.AddRange(RequestedUsers);
}
return u;
}

@ -24,7 +24,8 @@ Function.prototype.bind = function (parent) {
$(function () {
var searchSource = $("#search-template").html();
var useNewSearch = $('#useNewSearch').text() == 'True';
var searchSource = useNewSearch ? $("#search-templateNew").html() : $("#search-template").html();
var seasonsSource = $("#seasons-template").html();
var musicSource = $("#music-template").html();
var seasonsNumberSource = $("#seasonNumber-template").html();
@ -470,7 +471,11 @@ $(function () {
requested: result.requested,
approved: result.approved,
available: result.available,
url: result.plexUrl
url: result.plexUrl,
trailer: result.trailer,
homepage: result.homepage,
releaseDate: Humanize(result.releaseDate),
status: result.status
};
return context;

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: SearchLoadViewModel.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 Ombi.Core.SettingModels;
namespace Ombi.UI.Models
{
public class SearchLoadViewModel
{
public PlexRequestSettings Settings { get; set; }
public CustomizationSettings CustomizationSettings { get; set; }
}
}

@ -47,5 +47,8 @@ namespace Ombi.UI.Models
public double VoteAverage { get; set; }
public int VoteCount { get; set; }
public bool AlreadyInCp { get; set; }
public string Trailer { get; set; }
public string Homepage { get; set; }
public string ImdbId { get; set; }
}
}

@ -211,8 +211,8 @@ namespace Ombi.UI.Modules.Admin
Get["/headphones"] = _ => Headphones();
Post["/headphones"] = _ => SaveHeadphones();
Get["/newsletter"] = _ => Newsletter();
Post["/newsletter"] = _ => SaveNewsletter();
Get["/newsletter", true] = async (x, ct) => await Newsletter();
Post["/newsletter", true] = async (x, ct) => await SaveNewsletter();
Post["/createapikey"] = x => CreateApiKey();
@ -845,13 +845,13 @@ namespace Ombi.UI.Modules.Admin
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
}
private Negotiator Newsletter()
private async Task<Negotiator> Newsletter()
{
var settings = NewsLetterService.GetSettings();
var settings = await NewsLetterService.GetSettingsAsync();
return View["NewsletterSettings", settings];
}
private Response SaveNewsletter()
private async Task<Response> SaveNewsletter()
{
var settings = this.Bind<NewletterSettings>();
@ -859,9 +859,17 @@ namespace Ombi.UI.Modules.Admin
if (!valid.IsValid)
{
var error = valid.SendJsonError();
Log.Info("Error validating Headphones settings, message: {0}", error.Message);
Log.Info("Error validating Newsletter settings, message: {0}", error.Message);
return Response.AsJson(error);
}
// Make sure emails are setup
var emailSettings = await EmailService.GetSettingsAsync();
if (!emailSettings.Enabled)
{
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Please enable your email notifications" });
}
settings.SendRecentlyAddedEmail = settings.SendRecentlyAddedEmail;
var result = NewsLetterService.SaveSettings(settings);

@ -77,7 +77,7 @@ namespace Ombi.UI.Modules
ISettingsService<PlexSettings> plexService, ISettingsService<AuthenticationSettings> auth,
IRepository<UsersToNotify> u, ISettingsService<EmailNotificationSettings> email,
IIssueService issue, IAnalytics a, IRepository<RequestLimit> rl, ITransientFaultQueue tfQueue, IRepository<PlexContent> content,
ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher, ITraktApi traktApi)
ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher, ITraktApi traktApi, ISettingsService<CustomizationSettings> cus)
: base("search", prSettings, security)
{
Auth = auth;
@ -111,6 +111,7 @@ namespace Ombi.UI.Modules
WatcherCacher = watcherCacher;
RadarrCacher = radarrCacher;
TraktApi = traktApi;
CustomizationSettings = cus;
Get["SearchIndex", "/", true] = async (x, ct) => await RequestLoad();
@ -169,14 +170,22 @@ namespace Ombi.UI.Modules
private ITransientFaultQueue FaultQueue { get; }
private IRepository<RequestLimit> RequestLimitRepo { get; }
private IRadarrCacher RadarrCacher { get; }
private ISettingsService<CustomizationSettings> CustomizationSettings { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
private async Task<Negotiator> RequestLoad()
{
var settings = await PrService.GetSettingsAsync();
var custom = await CustomizationSettings.GetSettingsAsync();
var searchViewModel = new SearchLoadViewModel
{
Settings = settings,
CustomizationSettings = custom
};
return View["Search/Index", settings];
return View["Search/Index", searchViewModel];
}
private async Task<Response> UpcomingMovies()
@ -266,17 +275,6 @@ namespace Ombi.UI.Modules
var counter = 0;
foreach (var movie in apiMovies)
{
var imdbId = string.Empty;
if (counter <= 5) // Let's only do it for the first 5 items
{
var movieInfoTask = await MovieApi.GetMovieInformation(movie.Id).ConfigureAwait(false);
// TODO needs to be careful about this, it's adding extra time to search...
// https://www.themoviedb.org/talk/5807f4cdc3a36812160041f2
imdbId = movieInfoTask?.ImdbId;
counter++;
}
var viewMovie = new SearchMovieViewModel
{
Adult = movie.Adult,
@ -294,6 +292,28 @@ namespace Ombi.UI.Modules
VoteAverage = movie.VoteAverage,
VoteCount = movie.VoteCount
};
var imdbId = string.Empty;
if (counter <= 5) // Let's only do it for the first 5 items
{
var movieInfo = MovieApi.GetMovieInformationWithVideos(movie.Id);
// TODO needs to be careful about this, it's adding extra time to search...
// https://www.themoviedb.org/talk/5807f4cdc3a36812160041f2
viewMovie.ImdbId = movieInfo?.imdb_id;
viewMovie.Homepage = movieInfo?.homepage;
var videoId = movieInfo?.video ?? false
? movieInfo?.videos?.results?.FirstOrDefault()?.key
: string.Empty;
viewMovie.Trailer = string.IsNullOrEmpty(videoId)
? string.Empty
: $"https://www.youtube.com/watch?v={videoId}";
counter++;
}
var canSee = CanUserSeeThisRequest(viewMovie.Id, Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests), dbMovies);
var plexMovie = Checker.GetMovie(plexMovies.ToArray(), movie.Title, movie.ReleaseDate?.Year.ToString(),
imdbId);
@ -989,6 +1009,11 @@ namespace Ombi.UI.Modules
existingRequest.Episodes.AddRange(newEpisodes ?? Enumerable.Empty<EpisodesModel>());
// It's technically a new request now, so set the status to not approved.
var autoApprove = ShouldAutoApprove(RequestType.TvShow);
if (autoApprove)
{
return await SendTv(model, sonarrSettings, existingRequest, fullShowName, settings);
}
existingRequest.Approved = false;
return await AddUserToRequest(existingRequest, settings, fullShowName, true);
@ -1115,54 +1140,7 @@ namespace Ombi.UI.Modules
{
if (ShouldAutoApprove(RequestType.TvShow))
{
model.Approved = true;
var s = await sonarrSettings;
var sender = new TvSenderOld(SonarrApi, SickrageApi, Cache); // TODO put back
if (s.Enabled)
{
var result = await sender.SendToSonarr(s, model);
if (!string.IsNullOrEmpty(result?.title))
{
if (existingRequest != null)
{
return await UpdateRequest(model, settings,
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
}
return
await
AddRequest(model, settings,
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
}
Log.Debug("Error with sending to sonarr.");
return
Response.AsJson(ValidationHelper.SendSonarrError(result?.ErrorMessages ?? new List<string>()));
}
var srSettings = SickRageService.GetSettings();
if (srSettings.Enabled)
{
var result = sender.SendToSickRage(srSettings, model);
if (result?.result == "success")
{
return await AddRequest(model, settings,
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
}
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message = result?.message ?? Resources.UI.Search_SickrageError
});
}
if (!srSettings.Enabled && !s.Enabled)
{
return await AddRequest(model, settings, $"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
}
return
Response.AsJson(new JsonResponseModel { Result = false, Message = Resources.UI.Search_TvNotSetUp });
return await SendTv(model, sonarrSettings, existingRequest, fullShowName, settings);
}
return await AddRequest(model, settings, $"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
}
@ -1620,5 +1598,56 @@ namespace Ombi.UI.Modules
MostWatched,
Trending
}
private async Task<Response> SendTv(RequestedModel model, Task<SonarrSettings> sonarrSettings, RequestedModel existingRequest, string fullShowName, PlexRequestSettings settings)
{
model.Approved = true;
var s = await sonarrSettings;
var sender = new TvSenderOld(SonarrApi, SickrageApi, Cache); // TODO put back
if (s.Enabled)
{
var result = await sender.SendToSonarr(s, model);
if (!string.IsNullOrEmpty(result?.title))
{
if (existingRequest != null)
{
return await UpdateRequest(model, settings,
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
}
return
await
AddRequest(model, settings,
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
}
Log.Debug("Error with sending to sonarr.");
return
Response.AsJson(ValidationHelper.SendSonarrError(result?.ErrorMessages ?? new List<string>()));
}
var srSettings = SickRageService.GetSettings();
if (srSettings.Enabled)
{
var result = sender.SendToSickRage(srSettings, model);
if (result?.result == "success")
{
return await AddRequest(model, settings,
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
}
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message = result?.message ?? Resources.UI.Search_SickrageError
});
}
if (!srSettings.Enabled && !s.Enabled)
{
return await AddRequest(model, settings, $"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
}
return
Response.AsJson(new JsonResponseModel { Result = false, Message = Resources.UI.Search_TvNotSetUp });
}
}
}

@ -252,6 +252,7 @@
<Compile Include="Models\Requests\RequestsIndexViewModel.cs" />
<Compile Include="Models\RootFolderModel.cs" />
<Compile Include="Models\ScheduledJobsViewModel.cs" />
<Compile Include="Models\SearchLoadViewModel.cs" />
<Compile Include="Models\SearchViewModel.cs" />
<Compile Include="Models\SearchMusicViewModel.cs" />
<Compile Include="Models\SearchMovieViewModel.cs" />

@ -31,20 +31,7 @@
</div>
</div>
<div class="form-group">
<div class="checkbox">
@if (Model.EnableUserEmailNotifications)
{
<input type="checkbox" id="EnableUserEmailNotifications" name="EnableUserEmailNotifications" checked="checked"><label for="EnableUserEmailNotifications">Enable user email notifications</label>
}
else
{
<input type="checkbox" id="EnableUserEmailNotifications" name="EnableUserEmailNotifications"><label for="EnableUserEmailNotifications">Enable user email notifications</label>
}
</div>
</div>
<div class="form-group">
<div class="checkbox">
@ -59,7 +46,7 @@
</div>
</div>
<small>Please note that if user notifications is enabled, the email will get sent with the SMTP set-up below.</small>
<div class="form-group">
<label for="EmailHost" class="control-label">SMTP Host name or IP</label>
<div class="">
@ -82,12 +69,15 @@
<input type="text" class="form-control form-control-custom " id="EmailSender" name="EmailSender" value="@Model.EmailSender">
</div>
</div>
<small>The sender is who the email will be sent from, this can be for any email including user notification emails (if that is enabled).</small>
<div class="form-group">
<label for="RecipientEmail" class="control-label">Email Recipient</label>
<div>
<input type="text" class="form-control form-control-custom " id="RecipientEmail" name="RecipientEmail" value="@Model.RecipientEmail">
</div>
</div>
<small>The recipient email is used for emails going to the administrator.</small>

@ -16,35 +16,20 @@
<br />
@if (Model.SendRecentlyAddedEmail)
{
<input type="checkbox" id="SendRecentlyAddedEmail" name="SendRecentlyAddedEmail" checked="checked"><label for="SendRecentlyAddedEmail">Enable the newsletter of recently added content</label>
<input type="checkbox" id="SendRecentlyAddedEmail" name="SendRecentlyAddedEmail" checked="checked"><label for="SendRecentlyAddedEmail">Enable newsletter</label>
}
else
{
<input type="checkbox" id="SendRecentlyAddedEmail" name="SendRecentlyAddedEmail"><label for="SendRecentlyAddedEmail">Enable the newsletter of recently added content</label>
<input type="checkbox" id="SendRecentlyAddedEmail" name="SendRecentlyAddedEmail"><label for="SendRecentlyAddedEmail">Enable newslette</label>
}
</div>
</div>
<div class="form-group">
<div class="checkbox">
@if (Model.SendToPlexUsers)
{
<input type="checkbox" id="SendToPlexUsers" name="SendToPlexUsers" checked="checked"><label for="SendToPlexUsers">Send to all of your Plex 'Friends'</label>
}
else
{
<input type="checkbox" id="SendToPlexUsers" name="SendToPlexUsers"><label for="SendToPlexUsers">Send to all of your Plex 'Friends'</label>
}
</div>
</div>
<div class="form-group">
<br>
<br>
<label for="CustomUsers" class="control-label">Email Addresses to Send to (For users that are not in your Plex Friends)</label>
<label for="CustomUsers" class="control-label">Email Addresses to Send to (For users that are not in your User Management section)</label>
<small>You can add multiple email address by using the ; delimiter</small>
<div>
<input type="text" class="form-control form-control-custom " placeholder="first@address.com;second@address.com" id="CustomUsers" name="CustomUsers" value="@Model.CustomUsers">

@ -15,6 +15,8 @@
<form class="form-horizontal" method="POST" id="mainForm">
<fieldset>
<legend>Sonarr Settings</legend>
<input hidden="hidden" name="FullRootPath" id="fullRootPath" value="@Model.FullRootPath"/>
<div class="form-group">
<div class="checkbox">
@if (Model.Enabled)
@ -220,6 +222,8 @@
}
var qualityProfile = $("#profiles option:selected").val();
var rootFolder = $("#rootFolders option:selected").val();
var rootFolderPath = $('#rootFolders option:selected').text();
$('#fullRootPath').val(rootFolderPath);
var $form = $("#mainForm");

@ -40,6 +40,7 @@
</div>
</div>
<div class="form-group">
<label for="lang" class="control-label">Default Language</label>
<div id="langSelect">
@ -103,6 +104,7 @@
</div>
</div>
@Html.Checkbox(Model.Settings.NewSearch, "NewSearch", "Use New Search")
<div class="form-group">
<div>
<button type="submit" id="save" class="btn btn-primary-outline">Submit</button>

@ -1,5 +1,6 @@
@using Ombi.UI.Helpers
@using Ombi.UI.Resources
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<Ombi.UI.Models.SearchLoadViewModel>
@{
var baseUrl = Html.GetBaseUrl();
var url = string.Empty;
@ -9,6 +10,8 @@
}
}
<div>
<div hidden="hidden" id="useNewSearch">@Model.CustomizationSettings.NewSearch</div>
<h1 id="searchTitle">@UI.Search_Title</h1>
<h4>@UI.Search_Paragraph</h4>
<br />
@ -16,21 +19,21 @@
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
@if (Model.SearchForMovies)
@if (Model.Settings.SearchForMovies)
{
<li role="presentation" class="active">
<a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab"><i class="fa fa-film"></i> @UI.Search_Movies</a>
</li>
}
@if (Model.SearchForTvShows)
@if (Model.Settings.SearchForTvShows)
{
<li role="presentation">
<a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-television"></i> @UI.Search_TvShows</a>
</li>
}
@if (Model.SearchForMusic)
@if (Model.Settings.SearchForMusic)
{
<li role="presentation">
<a href="#MusicTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-music"></i>@UI.Search_Albums</a>
@ -41,7 +44,7 @@
<!-- Tab panes -->
<div class="tab-content">
@if (Model.SearchForMovies)
@if (Model.Settings.SearchForMovies)
{
<!-- Movie tab -->
<div role="tabpanel" class="tab-pane active" id="MoviesTab">
@ -70,7 +73,7 @@
}
@if (Model.SearchForTvShows)
@if (Model.Settings.SearchForTvShows)
{
<!-- TV tab -->
<div role="tabpanel" class="tab-pane" id="TvShowTab">
@ -99,7 +102,7 @@
</div>
}
@if (Model.SearchForMusic)
@if (Model.Settings.SearchForMusic)
{
<!-- Music tab -->
<div role="tabpanel" class="tab-pane" id="MusicTab">
@ -117,8 +120,170 @@
</div>
}
<script id="search-templateNew" type="text/x-handlebars-template">
<div class="row">
<div id="{{id}}imgDiv" class="col-sm-2">
{{#if_eq type "movie"}}
{{#if posterPath}}
<img class="img-responsive" src="https://image.tmdb.org/t/p/w150/{{posterPath}}" alt="poster">
{{/if}}
{{/if_eq}}
{{#if_eq type "tv"}}
{{#if posterPath}}
<img class="img-responsive" width="150" src="{{posterPath}}" alt="poster">
{{/if}}
{{/if_eq}}
</div>
<div class="col-sm-10">
<div>
<h4>
{{#if_eq type "movie"}}
<a href="https://www.themoviedb.org/movie/{{id}}/" target="_blank">
{{else}}
<a href="http://www.imdb.com/title/{{imdb}}/" target="_blank">
{{/if_eq}}
{{title}} ({{year}})
{{#if status}}
<span class="label label-primary" style="font-size:60%" target="_blank">{{status}}</span>
{{/if}}
</h4>
</a>
<div class="row">
<div class="col-md-7 col-xs-7">
{{#if available}}
<span class="label label-success">@UI.Search_Available_on_plex</span>
{{else}}
{{#if approved}}
<span class="label label-info">@UI.Search_Processing_Request</span>
{{else if requested}}
<span class="label label-warning">@UI.Search_Pending_approval</span>
{{else}}
<span class="label label-danger">@UI.Search_Not_Requested_Yet</span>
{{/if}}
{{/if}}
{{#if firstAired}}
<span class="label label-info" target="_blank">Air Date: {{firstAired}}</span>
{{/if}}
{{#if releaseDate}}
<span class="label label-info" target="_blank">Release Date: {{releaseDate}}</span>
{{/if}}
<span id="{{id}}netflixTab"></span>
</div>
<!--Info Labels-->
<div class="col-md-5 col-xs-5" style="text-align:right;">
{{#if homepage}}
<a href="{{homepage}}" target="_blank"><span class="label label-info">HomePage</span></a>
{{/if}}
{{#if trailer}}
<a href="{{trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
{{/if}}
</div>
</div>
<div class="row">
<!-- Description -->
<p style="font-size:0.9rem !important">{{overview}}</p>
<br />
<br />
</div>
<form method="POST" action="@url/search/request/{{type}}" id="form{{id}}">
<input name="{{type}}Id" type="text" value="{{id}}" hidden="hidden" />
{{#if_eq type "movie"}}
{{#if_eq available true}}
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button>
<br />
<br />
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
{{else}}
{{#if_eq requested true}}
<button style="text-align: right" class="btn btn-primary-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button>
{{else}}
<button id="{{id}}" style="text-align: right" class="btn btn-primary-outline requestMovie" type="submit"><i class="fa fa-plus"></i> @UI.Search_Request</button>
{{/if_eq}}
{{/if_eq}}
{{/if_eq}}
{{#if_eq type "tv"}}
{{#if_eq tvFullyAvailable true}}
@*//TODO Not used yet*@
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button><br />
{{else}}
{{#if_eq enableTvRequestsForOnlySeries true}}
<button id="{{id}}" style="text-align: right" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline{{/if}} btn-primary-outline dropdownTv" season-select="0" type="button"><i class="fa fa-plus"></i> @UI.Search_Request</button>
{{else}}
<div class="dropdown">
<button id="{{id}}" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline{{/if}} dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> {{#if available}}@UI.Search_Available{{else}}@UI.Search_Request {{/if}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a id="{{id}}" season-select="0" class="dropdownTv " href="#">@UI.Search_AllSeasons</a></li>
{{#if_eq disableTvRequestsBySeason false}}
<li><a id="{{id}}" season-select="1" class="dropdownTv" href="#">@UI.Search_FirstSeason</a></li>
<li><a id="{{id}}" season-select="2" class="dropdownTv" href="#">@UI.Search_LatestSeason</a></li>
<li><a id="SeasonSelect" data-identifier="{{id}}" data-toggle="modal" data-target="#seasonsModal" href="#">@UI.Search_SelectSeason...</a></li>
{{/if_eq}}
{{#if_eq disableTvRequestsByEpisode false}}
<li><a id="EpisodeSelect" data-identifier="{{id}}" data-toggle="modal" data-target="#episodesModal" href="#">@UI.Search_SelectEpisode...</a></li>
{{/if_eq}}
</ul>
</div>
{{/if_eq}}
{{#if available}}
<br />
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
{{/if}}
{{/if_eq}}
{{/if_eq}}
<br />
</form>
{{#if_eq available true}}
<form method="POST" action="@url/issues/nonrequestissue/" id="report{{id}}">
<input name="providerId" type="text" value="{{id}}" hidden="hidden" />
<input name="type" type="text" value="{{type}}" hidden="hidden" />
<div class="dropdown">
<button id="{{id}}" class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-exclamation"></i> @UI.Search_ReportIssue
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a id="{{id}}" issue-select="0" class="dropdownIssue" href="#">@UI.Issues_WrongAudio</a></li>
<li><a id="{{id}}" issue-select="1" class="dropdownIssue" href="#">@UI.Issues_NoSubs</a></li>
<li><a id="{{id}}" issue-select="2" class="dropdownIssue" href="#">@UI.Issues_WrongContent</a></li>
<li><a id="{{id}}" issue-select="3" class="dropdownIssue" href="#">@UI.Issues_Playback</a></li>
<li><a id="{{id}}" issue-select="4" class="dropdownIssue" data-identifier="{{id}}" data-type="{{type}}" href="#" data-toggle="modal" data-target="#issuesModal">@UI.Issues_Other</a></li>
</ul>
</div>
</form>
{{/if_eq}}
</div>
</div>
<div class="col-sm-12">
</div>
</div>
<hr />
</script>
<!-- Movie and TV Results template -->
<script id="search-template" type="text/x-handlebars-template">
<script id="search-template" type="text/x-handlebars-template">
<div class="row">
<div id="{{id}}imgDiv" class="col-sm-2">
@ -134,28 +299,30 @@
{{/if_eq}}
</div>
<div class="col-sm-5 ">
<div class="col-sm-8">
<div>
{{#if_eq type "movie"}}
<a href="https://www.themoviedb.org/movie/{{id}}/" target="_blank">
<h4>{{title}} ({{year}})</h4>
</a>
{{else}}
<a href="http://www.imdb.com/title/{{imdb}}/" target="_blank">
<h4>{{title}} ({{year}})</h4>
</a>
<h4>
<a href="http://www.imdb.com/title/{{imdb}}/" target="_blank">
{{title}} ({{year}})
</a>{{#if status}}<span class="label label-primary" style="font-size:60%" target="_blank">{{status}}</span>{{/if}}
</h4>
{{/if_eq}}
{{#if status}}
<span class="label label-info" target="_blank">{{status}}</span>
{{/if}}
{{#if homepage}}
<a href="{{homepage}}" target="_blank"><span class="label label-info">HomePage</span></a>
{{/if}}
{{#if trailer}}
<a href="{{trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
{{/if}}
{{#if firstAired}}
<span class="label label-info" target="_blank">First Aired: {{firstAired}}</span>
<span class="label label-info" target="_blank">Air Date: {{firstAired}}</span>
{{/if}}
{{#if releaseDate}}
<span class="label label-info" target="_blank">Release Date: {{releaseDate}}</span>
{{/if}}
{{#if available}}
<span class="label label-success">@UI.Search_Available_on_plex</span>
@ -169,14 +336,22 @@
{{/if}}
{{/if}}
<span id="{{id}}netflixTab"></span>
{{#if homepage}}
<a href="{{homepage}}" target="_blank"><span class="label label-info">HomePage</span></a>
{{/if}}
{{#if trailer}}
<a href="{{trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
{{/if}}
<br />
<br />
</div>
<p>{{overview}}</p>
<p style="font-size:0.9rem !important">{{overview}}</p>
</div>
<div class="col-sm-2 col-sm-push-3">
<div class="col-sm-2">
<form method="POST" action="@url/search/request/{{type}}" id="form{{id}}">
<input name="{{type}}Id" type="text" value="{{id}}" hidden="hidden" />
{{#if_eq type "movie"}}

Loading…
Cancel
Save