mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-16 02:02:55 -07:00
Finished #415
This commit is contained in:
parent
2aebbe0259
commit
7db336e202
19 changed files with 229 additions and 89 deletions
|
@ -24,6 +24,9 @@
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace PlexRequests.Core.SettingModels
|
namespace PlexRequests.Core.SettingModels
|
||||||
{
|
{
|
||||||
public sealed class PlexSettings : ExternalSettings
|
public sealed class PlexSettings : ExternalSettings
|
||||||
|
@ -36,5 +39,6 @@ namespace PlexRequests.Core.SettingModels
|
||||||
public bool EnableTvEpisodeSearching { get; set; }
|
public bool EnableTvEpisodeSearching { get; set; }
|
||||||
|
|
||||||
public string PlexAuthToken { get; set; }
|
public string PlexAuthToken { get; set; }
|
||||||
|
public string MachineIdentifier { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
using Mono.Data.Sqlite;
|
using Mono.Data.Sqlite;
|
||||||
|
@ -66,6 +67,11 @@ namespace PlexRequests.Core
|
||||||
{
|
{
|
||||||
MigrateToVersion1900();
|
MigrateToVersion1900();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(version > 1899 && version <= 1910)
|
||||||
|
{
|
||||||
|
MigrateToVersion1910();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Db.DbConnection().ConnectionString;
|
return Db.DbConnection().ConnectionString;
|
||||||
|
@ -244,5 +250,30 @@ namespace PlexRequests.Core
|
||||||
Log.Error(e);
|
Log.Error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Migrates to version1910.
|
||||||
|
/// </summary>
|
||||||
|
public void MigrateToVersion1910()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get the new machine Identifier
|
||||||
|
var settings = new SettingsServiceV2<PlexSettings>(new SettingsJsonRepository(Db, new MemoryCacheProvider()));
|
||||||
|
var plex = settings.GetSettings();
|
||||||
|
if (!string.IsNullOrEmpty(plex.PlexAuthToken))
|
||||||
|
{
|
||||||
|
var api = new PlexApi(new ApiRequest());
|
||||||
|
var server = api.GetServer(plex.PlexAuthToken); // Get the server info
|
||||||
|
plex.MachineIdentifier = server.Server.FirstOrDefault(x => x.AccessToken == plex.PlexAuthToken)?.MachineIdentifier;
|
||||||
|
|
||||||
|
settings.SaveSettings(plex); // Save the new settings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,12 @@ namespace PlexRequests.Helpers.Tests
|
||||||
return PlexHelper.GetSeasonNumberFromTitle(title);
|
return PlexHelper.GetSeasonNumberFromTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(MediaUrls))]
|
||||||
|
public string GetPlexMediaUrlTest(string machineId, string mediaId)
|
||||||
|
{
|
||||||
|
return PlexHelper.GetPlexMediaUrl(machineId, mediaId);
|
||||||
|
}
|
||||||
|
|
||||||
private static IEnumerable<TestCaseData> PlexGuids
|
private static IEnumerable<TestCaseData> PlexGuids
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -75,6 +81,15 @@ namespace PlexRequests.Helpers.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TestCaseData> MediaUrls
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData("abcd","99").Returns("https://app.plex.tv/web/app#!/server/abcd/details/%2Flibrary%2Fmetadata%2F99").SetName("Test 1");
|
||||||
|
yield return new TestCaseData("a54d1db669799308cd704b791f331eca6648b952", "51").Returns("https://app.plex.tv/web/app#!/server/a54d1db669799308cd704b791f331eca6648b952/details/%2Flibrary%2Fmetadata%2F51").SetName("Test 2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static IEnumerable<TestCaseData> SeasonNumbers
|
private static IEnumerable<TestCaseData> SeasonNumbers
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
@ -95,6 +95,13 @@ namespace PlexRequests.Helpers
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetPlexMediaUrl(string machineId, string mediaId)
|
||||||
|
{
|
||||||
|
var url =
|
||||||
|
$"https://app.plex.tv/web/app#!/server/{machineId}/details/%2Flibrary%2Fmetadata%2F{mediaId}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EpisodeModelHelper
|
public class EpisodeModelHelper
|
||||||
|
|
|
@ -242,6 +242,7 @@ namespace PlexRequests.Services.Tests
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedMovies);
|
CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedMovies);
|
||||||
|
SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
|
||||||
var movies = Checker.GetPlexMovies();
|
var movies = Checker.GetPlexMovies();
|
||||||
|
|
||||||
Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
||||||
|
@ -258,6 +259,7 @@ namespace PlexRequests.Services.Tests
|
||||||
new Directory1 {Type = "show", Title = "title1", Year = "2016", ProviderId = "1212", Seasons = new List<Directory1>()}
|
new Directory1 {Type = "show", Title = "title1", Year = "2016", ProviderId = "1212", Seasons = new List<Directory1>()}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
|
||||||
CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedTv);
|
CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedTv);
|
||||||
var movies = Checker.GetPlexTvShows();
|
var movies = Checker.GetPlexTvShows();
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ namespace PlexRequests.Services.Interfaces
|
||||||
List<PlexAlbum> GetPlexAlbums();
|
List<PlexAlbum> GetPlexAlbums();
|
||||||
bool IsAlbumAvailable(PlexAlbum[] plexAlbums, string title, string year, string artist);
|
bool IsAlbumAvailable(PlexAlbum[] plexAlbums, string title, string year, string artist);
|
||||||
bool IsEpisodeAvailable(string theTvDbId, int season, int episode);
|
bool IsEpisodeAvailable(string theTvDbId, int season, int episode);
|
||||||
|
PlexAlbum GetAlbum(PlexAlbum[] plexAlbums, string title, string year, string artist);
|
||||||
|
PlexMovie GetMovie(PlexMovie[] plexMovies, string title, string year, string providerId = null);
|
||||||
|
PlexTvShow GetTvShow(PlexTvShow[] plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the episode's stored in the cache.
|
/// Gets the episode's stored in the cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -158,6 +158,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
|
|
||||||
public List<PlexMovie> GetPlexMovies()
|
public List<PlexMovie> GetPlexMovies()
|
||||||
{
|
{
|
||||||
|
var settings = Plex.GetSettings();
|
||||||
var movies = new List<PlexMovie>();
|
var movies = new List<PlexMovie>();
|
||||||
var libs = Cache.Get<List<PlexSearch>>(CacheKeys.PlexLibaries);
|
var libs = Cache.Get<List<PlexSearch>>(CacheKeys.PlexLibaries);
|
||||||
if (libs != null)
|
if (libs != null)
|
||||||
|
@ -175,6 +176,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
ReleaseYear = video.Year,
|
ReleaseYear = video.Year,
|
||||||
Title = video.Title,
|
Title = video.Title,
|
||||||
ProviderId = video.ProviderId,
|
ProviderId = video.ProviderId,
|
||||||
|
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, video.RatingKey)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,6 +184,12 @@ namespace PlexRequests.Services.Jobs
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsMovieAvailable(PlexMovie[] plexMovies, string title, string year, string providerId = null)
|
public bool IsMovieAvailable(PlexMovie[] plexMovies, string title, string year, string providerId = null)
|
||||||
|
{
|
||||||
|
var movie = GetMovie(plexMovies, title, year, providerId);
|
||||||
|
return movie != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlexMovie GetMovie(PlexMovie[] plexMovies, string title, string year, string providerId = null)
|
||||||
{
|
{
|
||||||
var advanced = !string.IsNullOrEmpty(providerId);
|
var advanced = !string.IsNullOrEmpty(providerId);
|
||||||
foreach (var movie in plexMovies)
|
foreach (var movie in plexMovies)
|
||||||
|
@ -191,20 +199,21 @@ namespace PlexRequests.Services.Jobs
|
||||||
if (!string.IsNullOrEmpty(movie.ProviderId) &&
|
if (!string.IsNullOrEmpty(movie.ProviderId) &&
|
||||||
movie.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
|
movie.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
return true;
|
return movie;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (movie.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
|
if (movie.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
|
||||||
movie.ReleaseYear.Equals(year, StringComparison.CurrentCultureIgnoreCase))
|
movie.ReleaseYear.Equals(year, StringComparison.CurrentCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
return true;
|
return movie;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PlexTvShow> GetPlexTvShows()
|
public List<PlexTvShow> GetPlexTvShows()
|
||||||
{
|
{
|
||||||
|
var settings = Plex.GetSettings();
|
||||||
var shows = new List<PlexTvShow>();
|
var shows = new List<PlexTvShow>();
|
||||||
var libs = Cache.Get<List<PlexSearch>>(CacheKeys.PlexLibaries);
|
var libs = Cache.Get<List<PlexSearch>>(CacheKeys.PlexLibaries);
|
||||||
if (libs != null)
|
if (libs != null)
|
||||||
|
@ -224,7 +233,9 @@ namespace PlexRequests.Services.Jobs
|
||||||
Title = x.Title,
|
Title = x.Title,
|
||||||
ReleaseYear = x.Year,
|
ReleaseYear = x.Year,
|
||||||
ProviderId = x.ProviderId,
|
ProviderId = x.ProviderId,
|
||||||
Seasons = x.Seasons?.Select(d => PlexHelper.GetSeasonNumberFromTitle(d.Title)).ToArray()
|
Seasons = x.Seasons?.Select(d => PlexHelper.GetSeasonNumberFromTitle(d.Title)).ToArray(),
|
||||||
|
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, x.RatingKey)
|
||||||
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,6 +243,14 @@ namespace PlexRequests.Services.Jobs
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsTvShowAvailable(PlexTvShow[] plexShows, string title, string year, string providerId = null, int[] seasons = null)
|
public bool IsTvShowAvailable(PlexTvShow[] plexShows, string title, string year, string providerId = null, int[] seasons = null)
|
||||||
|
{
|
||||||
|
var show = GetTvShow(plexShows, title, year, providerId, seasons);
|
||||||
|
return show != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public PlexTvShow GetTvShow(PlexTvShow[] plexShows, string title, string year, string providerId = null,
|
||||||
|
int[] seasons = null)
|
||||||
{
|
{
|
||||||
var advanced = !string.IsNullOrEmpty(providerId);
|
var advanced = !string.IsNullOrEmpty(providerId);
|
||||||
foreach (var show in plexShows)
|
foreach (var show in plexShows)
|
||||||
|
@ -242,23 +261,23 @@ namespace PlexRequests.Services.Jobs
|
||||||
{
|
{
|
||||||
if (seasons.Any(season => show.Seasons.Contains(season)))
|
if (seasons.Any(season => show.Seasons.Contains(season)))
|
||||||
{
|
{
|
||||||
return true;
|
return show;
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(show.ProviderId) &&
|
if (!string.IsNullOrEmpty(show.ProviderId) &&
|
||||||
show.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
|
show.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
return true;
|
return show;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (show.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
|
if (show.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
|
||||||
show.ReleaseYear.Equals(year, StringComparison.CurrentCultureIgnoreCase))
|
show.ReleaseYear.Equals(year, StringComparison.CurrentCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
return true;
|
return show;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsEpisodeAvailable(string theTvDbId, int season, int episode)
|
public bool IsEpisodeAvailable(string theTvDbId, int season, int episode)
|
||||||
|
@ -328,6 +347,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
|
|
||||||
public List<PlexAlbum> GetPlexAlbums()
|
public List<PlexAlbum> GetPlexAlbums()
|
||||||
{
|
{
|
||||||
|
var settings = Plex.GetSettings();
|
||||||
var albums = new List<PlexAlbum>();
|
var albums = new List<PlexAlbum>();
|
||||||
var libs = Cache.Get<List<PlexSearch>>(CacheKeys.PlexLibaries);
|
var libs = Cache.Get<List<PlexSearch>>(CacheKeys.PlexLibaries);
|
||||||
if (libs != null)
|
if (libs != null)
|
||||||
|
@ -344,7 +364,8 @@ namespace PlexRequests.Services.Jobs
|
||||||
{
|
{
|
||||||
Title = x.Title,
|
Title = x.Title,
|
||||||
ReleaseYear = x.Year,
|
ReleaseYear = x.Year,
|
||||||
Artist = x.ParentTitle
|
Artist = x.ParentTitle,
|
||||||
|
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, x.RatingKey)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,7 +376,13 @@ namespace PlexRequests.Services.Jobs
|
||||||
{
|
{
|
||||||
return plexAlbums.Any(x =>
|
return plexAlbums.Any(x =>
|
||||||
x.Title.Contains(title) &&
|
x.Title.Contains(title) &&
|
||||||
//x.ReleaseYear.Equals(year, StringComparison.CurrentCultureIgnoreCase) &&
|
x.Artist.Equals(artist, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlexAlbum GetAlbum(PlexAlbum[] plexAlbums, string title, string year, string artist)
|
||||||
|
{
|
||||||
|
return plexAlbums.FirstOrDefault(x =>
|
||||||
|
x.Title.Contains(title) &&
|
||||||
x.Artist.Equals(artist, StringComparison.CurrentCultureIgnoreCase));
|
x.Artist.Equals(artist, StringComparison.CurrentCultureIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
namespace PlexRequests.Services.Models
|
namespace PlexRequests.Services.Models
|
||||||
{
|
{
|
||||||
public class PlexAlbum
|
public class PlexAlbum
|
||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Artist { get; set; }
|
public string Artist { get; set; }
|
||||||
public string ReleaseYear { get; set; }
|
public string ReleaseYear { get; set; }
|
||||||
}
|
public string Url { get; set; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
namespace PlexRequests.Services.Models
|
namespace PlexRequests.Services.Models
|
||||||
{
|
{
|
||||||
public class PlexMovie
|
public class PlexMovie
|
||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string ReleaseYear { get; set; }
|
public string ReleaseYear { get; set; }
|
||||||
public string ProviderId { get; set; }
|
public string ProviderId { get; set; }
|
||||||
}
|
public string Url { get; set; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,5 +6,6 @@
|
||||||
public string ReleaseYear { get; set; }
|
public string ReleaseYear { get; set; }
|
||||||
public string ProviderId { get; set; }
|
public string ProviderId { get; set; }
|
||||||
public int[] Seasons { get; set; }
|
public int[] Seasons { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
9
PlexRequests.UI/Content/search.js
vendored
9
PlexRequests.UI/Content/search.js
vendored
|
@ -429,7 +429,8 @@ $(function () {
|
||||||
imdb: result.imdbId,
|
imdb: result.imdbId,
|
||||||
requested: result.requested,
|
requested: result.requested,
|
||||||
approved: result.approved,
|
approved: result.approved,
|
||||||
available: result.available
|
available: result.available,
|
||||||
|
url: result.plexUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
@ -450,7 +451,8 @@ $(function () {
|
||||||
approved: result.approved,
|
approved: result.approved,
|
||||||
available: result.available,
|
available: result.available,
|
||||||
episodes: result.episodes,
|
episodes: result.episodes,
|
||||||
tvFullyAvailable: result.tvFullyAvailable
|
tvFullyAvailable: result.tvFullyAvailable,
|
||||||
|
url: result.plexUrl
|
||||||
};
|
};
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
@ -470,7 +472,8 @@ $(function () {
|
||||||
country: result.country,
|
country: result.country,
|
||||||
requested: result.requested,
|
requested: result.requested,
|
||||||
approved: result.approved,
|
approved: result.approved,
|
||||||
available: result.available
|
available: result.available,
|
||||||
|
url: result.plexUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
|
@ -1,37 +1,38 @@
|
||||||
#region Copyright
|
#region Copyright
|
||||||
// /************************************************************************
|
// /************************************************************************
|
||||||
// Copyright (c) 2016 Jamie Rees
|
// Copyright (c) 2016 Jamie Rees
|
||||||
// File: SearchTvShowViewModel.cs
|
// File: SearchTvShowViewModel.cs
|
||||||
// Created By: Jamie Rees
|
// Created By: Jamie Rees
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
// a copy of this software and associated documentation files (the
|
||||||
// "Software"), to deal in the Software without restriction, including
|
// "Software"), to deal in the Software without restriction, including
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
// the following conditions:
|
// the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be
|
// The above copyright notice and this permission notice shall be
|
||||||
// included in all copies or substantial portions of the Software.
|
// included in all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
namespace PlexRequests.UI.Models
|
namespace PlexRequests.UI.Models
|
||||||
{
|
{
|
||||||
public class SearchViewModel
|
public class SearchViewModel
|
||||||
{
|
{
|
||||||
public bool Approved { get; set; }
|
public bool Approved { get; set; }
|
||||||
public bool Requested { get; set; }
|
public bool Requested { get; set; }
|
||||||
public bool Available { get; set; }
|
public bool Available { get; set; }
|
||||||
}
|
public string PlexUrl { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -31,5 +31,6 @@ namespace PlexRequests.UI.Models
|
||||||
public const string UsernameKey = "Username";
|
public const string UsernameKey = "Username";
|
||||||
public const string ClientDateTimeOffsetKey = "ClientDateTimeOffset";
|
public const string ClientDateTimeOffsetKey = "ClientDateTimeOffset";
|
||||||
public const string UserWizardPlexAuth = nameof(UserWizardPlexAuth);
|
public const string UserWizardPlexAuth = nameof(UserWizardPlexAuth);
|
||||||
|
public const string UserWizardMachineId = nameof(UserWizardMachineId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ namespace PlexRequests.UI.Modules
|
||||||
Post["/couchpotato"] = _ => SaveCouchPotato();
|
Post["/couchpotato"] = _ => SaveCouchPotato();
|
||||||
|
|
||||||
Get["/plex"] = _ => Plex();
|
Get["/plex"] = _ => Plex();
|
||||||
Post["/plex"] = _ => SavePlex();
|
Post["/plex", true] = async (x, ct) => await SavePlex();
|
||||||
|
|
||||||
Get["/sonarr"] = _ => Sonarr();
|
Get["/sonarr"] = _ => Sonarr();
|
||||||
Post["/sonarr"] = _ => SaveSonarr();
|
Post["/sonarr"] = _ => SaveSonarr();
|
||||||
|
@ -170,13 +170,13 @@ namespace PlexRequests.UI.Modules
|
||||||
Post["/sickrage"] = _ => SaveSickrage();
|
Post["/sickrage"] = _ => SaveSickrage();
|
||||||
|
|
||||||
Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles();
|
Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles();
|
||||||
Post["/cpprofiles", true] = async (x,ct) => await GetCpProfiles();
|
Post["/cpprofiles", true] = async (x, ct) => await GetCpProfiles();
|
||||||
Post["/cpapikey"] = x => GetCpApiKey();
|
Post["/cpapikey"] = x => GetCpApiKey();
|
||||||
|
|
||||||
Get["/emailnotification"] = _ => EmailNotifications();
|
Get["/emailnotification"] = _ => EmailNotifications();
|
||||||
Post["/emailnotification"] = _ => SaveEmailNotifications();
|
Post["/emailnotification"] = _ => SaveEmailNotifications();
|
||||||
Post["/testemailnotification"] = _ => TestEmailNotifications();
|
Post["/testemailnotification"] = _ => TestEmailNotifications();
|
||||||
Get["/status", true] = async (x,ct) => await Status();
|
Get["/status", true] = async (x, ct) => await Status();
|
||||||
|
|
||||||
Get["/pushbulletnotification"] = _ => PushbulletNotifications();
|
Get["/pushbulletnotification"] = _ => PushbulletNotifications();
|
||||||
Post["/pushbulletnotification"] = _ => SavePushbulletNotifications();
|
Post["/pushbulletnotification"] = _ => SavePushbulletNotifications();
|
||||||
|
@ -268,7 +268,7 @@ namespace PlexRequests.UI.Modules
|
||||||
Analytics.TrackEventAsync(Category.Admin, Action.Save, "CollectAnalyticData turned off", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
Analytics.TrackEventAsync(Category.Admin, Action.Save, "CollectAnalyticData turned off", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
}
|
}
|
||||||
var result = PrService.SaveSettings(model);
|
var result = PrService.SaveSettings(model);
|
||||||
|
|
||||||
Analytics.TrackEventAsync(Category.Admin, Action.Save, "PlexRequestSettings", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
Analytics.TrackEventAsync(Category.Admin, Action.Save, "PlexRequestSettings", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
return Response.AsJson(result
|
return Response.AsJson(result
|
||||||
? new JsonResponseModel { Result = true }
|
? new JsonResponseModel { Result = true }
|
||||||
|
@ -377,7 +377,7 @@ namespace PlexRequests.UI.Modules
|
||||||
return View["Plex", settings];
|
return View["Plex", settings];
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response SavePlex()
|
private async Task<Response> SavePlex()
|
||||||
{
|
{
|
||||||
var plexSettings = this.Bind<PlexSettings>();
|
var plexSettings = this.Bind<PlexSettings>();
|
||||||
var valid = this.Validate(plexSettings);
|
var valid = this.Validate(plexSettings);
|
||||||
|
@ -386,8 +386,11 @@ namespace PlexRequests.UI.Modules
|
||||||
return Response.AsJson(valid.SendJsonError());
|
return Response.AsJson(valid.SendJsonError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Lookup identifier
|
||||||
|
var server = PlexApi.GetServer(plexSettings.PlexAuthToken);
|
||||||
|
plexSettings.MachineIdentifier = server.Server.FirstOrDefault(x => x.AccessToken == plexSettings.PlexAuthToken)?.MachineIdentifier;
|
||||||
|
|
||||||
var result = PlexService.SaveSettings(plexSettings);
|
var result = await PlexService.SaveSettingsAsync(plexSettings);
|
||||||
|
|
||||||
return Response.AsJson(result
|
return Response.AsJson(result
|
||||||
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Plex!" }
|
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Plex!" }
|
||||||
|
@ -517,7 +520,7 @@ namespace PlexRequests.UI.Modules
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(settings.EmailUsername) || string.IsNullOrEmpty(settings.EmailPassword))
|
if (string.IsNullOrEmpty(settings.EmailUsername) || string.IsNullOrEmpty(settings.EmailPassword))
|
||||||
{
|
{
|
||||||
return Response.AsJson(new JsonResponseModel {Result = false, Message = "SMTP Authentication is enabled, please specify a username and password"});
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "SMTP Authentication is enabled, please specify a username and password" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,7 +545,7 @@ namespace PlexRequests.UI.Modules
|
||||||
{
|
{
|
||||||
var checker = new StatusChecker();
|
var checker = new StatusChecker();
|
||||||
var status = await Cache.GetOrSetAsync(CacheKeys.LastestProductVersion, async () => await checker.GetStatus(), 30);
|
var status = await Cache.GetOrSetAsync(CacheKeys.LastestProductVersion, async () => await checker.GetStatus(), 30);
|
||||||
var md = new Markdown(new MarkdownOptions { AutoNewLines = true, AutoHyperlink = true});
|
var md = new Markdown(new MarkdownOptions { AutoNewLines = true, AutoHyperlink = true });
|
||||||
status.ReleaseNotes = md.Transform(status.ReleaseNotes);
|
status.ReleaseNotes = md.Transform(status.ReleaseNotes);
|
||||||
return View["Status", status];
|
return View["Status", status];
|
||||||
}
|
}
|
||||||
|
@ -711,7 +714,7 @@ namespace PlexRequests.UI.Modules
|
||||||
private Response GetCpApiKey()
|
private Response GetCpApiKey()
|
||||||
{
|
{
|
||||||
var settings = this.Bind<CouchPotatoSettings>();
|
var settings = this.Bind<CouchPotatoSettings>();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(settings.Username) || string.IsNullOrEmpty(settings.Password))
|
if (string.IsNullOrEmpty(settings.Username) || string.IsNullOrEmpty(settings.Password))
|
||||||
{
|
{
|
||||||
return Response.AsJson(new { Message = "Please enter a username and password to request the Api Key", Result = false });
|
return Response.AsJson(new { Message = "Please enter a username and password to request the Api Key", Result = false });
|
||||||
|
@ -938,12 +941,12 @@ namespace PlexRequests.UI.Modules
|
||||||
{
|
{
|
||||||
await LogsRepo.DeleteAsync(logEntity);
|
await LogsRepo.DeleteAsync(logEntity);
|
||||||
}
|
}
|
||||||
return Response.AsJson(new JsonResponseModel { Result = true, Message = "Logs cleared successfully."});
|
return Response.AsJson(new JsonResponseModel { Result = true, Message = "Logs cleared successfully." });
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.Error(e);
|
Log.Error(e);
|
||||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = e.Message });
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = e.Message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
Get["movie/{searchTerm}", true] = async (x, ct) => await SearchMovie((string)x.searchTerm);
|
Get["movie/{searchTerm}", true] = async (x, ct) => await SearchMovie((string)x.searchTerm);
|
||||||
Get["tv/{searchTerm}", true] = async (x, ct) => await SearchTvShow((string)x.searchTerm);
|
Get["tv/{searchTerm}", true] = async (x, ct) => await SearchTvShow((string)x.searchTerm);
|
||||||
Get["music/{searchTerm}", true] = async (x, ct) => await SearchMusic((string)x.searchTerm);
|
Get["music/{searchTerm}", true] = async (x, ct) => await SearchAlbum((string)x.searchTerm);
|
||||||
Get["music/coverArt/{id}"] = p => GetMusicBrainzCoverArt((string)p.id);
|
Get["music/coverArt/{id}"] = p => GetMusicBrainzCoverArt((string)p.id);
|
||||||
|
|
||||||
Get["movie/upcoming", true] = async (x, ct) => await UpcomingMovies();
|
Get["movie/upcoming", true] = async (x, ct) => await UpcomingMovies();
|
||||||
|
@ -252,9 +252,11 @@ namespace PlexRequests.UI.Modules
|
||||||
VoteCount = movie.VoteCount
|
VoteCount = movie.VoteCount
|
||||||
};
|
};
|
||||||
var canSee = CanUserSeeThisRequest(viewMovie.Id, settings.UsersCanViewOnlyOwnRequests, dbMovies);
|
var canSee = CanUserSeeThisRequest(viewMovie.Id, settings.UsersCanViewOnlyOwnRequests, dbMovies);
|
||||||
if (Checker.IsMovieAvailable(plexMovies.ToArray(), movie.Title, movie.ReleaseDate?.Year.ToString()))
|
var plexMovie = Checker.GetMovie(plexMovies.ToArray(), movie.Title, movie.ReleaseDate?.Year.ToString());
|
||||||
|
if (plexMovie != null)
|
||||||
{
|
{
|
||||||
viewMovie.Available = true;
|
viewMovie.Available = true;
|
||||||
|
viewMovie.PlexUrl = plexMovie.Url;
|
||||||
}
|
}
|
||||||
else if (dbMovies.ContainsKey(movie.Id) && canSee) // compare to the requests db
|
else if (dbMovies.ContainsKey(movie.Id) && canSee) // compare to the requests db
|
||||||
{
|
{
|
||||||
|
@ -343,9 +345,12 @@ namespace PlexRequests.UI.Modules
|
||||||
providerId = viewT.Id.ToString();
|
providerId = viewT.Id.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Checker.IsTvShowAvailable(plexTvShows.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), providerId))
|
var plexShow = Checker.GetTvShow(plexTvShows.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4),
|
||||||
|
providerId);
|
||||||
|
if (plexShow != null)
|
||||||
{
|
{
|
||||||
viewT.Available = true;
|
viewT.Available = true;
|
||||||
|
viewT.PlexUrl = plexShow.Url;
|
||||||
}
|
}
|
||||||
else if (t.show?.externals?.thetvdb != null)
|
else if (t.show?.externals?.thetvdb != null)
|
||||||
{
|
{
|
||||||
|
@ -371,7 +376,7 @@ namespace PlexRequests.UI.Modules
|
||||||
return Response.AsJson(viewTv);
|
return Response.AsJson(viewTv);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Response> SearchMusic(string searchTerm)
|
private async Task<Response> SearchAlbum(string searchTerm)
|
||||||
{
|
{
|
||||||
Analytics.TrackEventAsync(Category.Search, Action.Album, searchTerm, Username, CookieHelper.GetAnalyticClientId(Cookies));
|
Analytics.TrackEventAsync(Category.Search, Action.Album, searchTerm, Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
var apiAlbums = new List<Release>();
|
var apiAlbums = new List<Release>();
|
||||||
|
@ -405,9 +410,11 @@ namespace PlexRequests.UI.Modules
|
||||||
DateTime release;
|
DateTime release;
|
||||||
DateTimeHelper.CustomParse(a.ReleaseEvents?.FirstOrDefault()?.date, out release);
|
DateTimeHelper.CustomParse(a.ReleaseEvents?.FirstOrDefault()?.date, out release);
|
||||||
var artist = a.ArtistCredit?.FirstOrDefault()?.artist;
|
var artist = a.ArtistCredit?.FirstOrDefault()?.artist;
|
||||||
if (Checker.IsAlbumAvailable(plexAlbums.ToArray(), a.title, release.ToString("yyyy"), artist?.name))
|
var plexAlbum = Checker.GetAlbum(plexAlbums.ToArray(), a.title, release.ToString("yyyy"), artist?.name);
|
||||||
|
if (plexAlbum != null)
|
||||||
{
|
{
|
||||||
viewA.Available = true;
|
viewA.Available = true;
|
||||||
|
viewA.PlexUrl = plexAlbum.Url;
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(a.id) && dbAlbum.ContainsKey(a.id))
|
if (!string.IsNullOrEmpty(a.id) && dbAlbum.ContainsKey(a.id))
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,7 +34,7 @@ using Nancy.Extensions;
|
||||||
using Nancy.ModelBinding;
|
using Nancy.ModelBinding;
|
||||||
using Nancy.Responses.Negotiation;
|
using Nancy.Responses.Negotiation;
|
||||||
using Nancy.Validation;
|
using Nancy.Validation;
|
||||||
|
using NLog;
|
||||||
using PlexRequests.Api.Interfaces;
|
using PlexRequests.Api.Interfaces;
|
||||||
using PlexRequests.Core;
|
using PlexRequests.Core;
|
||||||
using PlexRequests.Core.SettingModels;
|
using PlexRequests.Core.SettingModels;
|
||||||
|
@ -84,7 +84,9 @@ namespace PlexRequests.UI.Modules
|
||||||
private ICustomUserMapper Mapper { get; }
|
private ICustomUserMapper Mapper { get; }
|
||||||
private IAnalytics Analytics { get; }
|
private IAnalytics Analytics { get; }
|
||||||
|
|
||||||
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
|
||||||
private Response PlexAuth()
|
private Response PlexAuth()
|
||||||
{
|
{
|
||||||
var user = this.Bind<PlexAuth>();
|
var user = this.Bind<PlexAuth>();
|
||||||
|
@ -103,9 +105,10 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
// Set the auth token in the session so we can use it in the next form
|
// Set the auth token in the session so we can use it in the next form
|
||||||
Session[SessionKeys.UserWizardPlexAuth] = model.user.authentication_token;
|
Session[SessionKeys.UserWizardPlexAuth] = model.user.authentication_token;
|
||||||
|
|
||||||
var servers = PlexApi.GetServer(model.user.authentication_token);
|
var servers = PlexApi.GetServer(model.user.authentication_token);
|
||||||
var firstServer = servers.Server.FirstOrDefault();
|
var firstServer = servers.Server.FirstOrDefault();
|
||||||
|
|
||||||
return Response.AsJson(new { Result = true, firstServer?.Port, Ip = firstServer?.LocalAddresses, firstServer?.Scheme });
|
return Response.AsJson(new { Result = true, firstServer?.Port, Ip = firstServer?.LocalAddresses, firstServer?.Scheme });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +122,20 @@ namespace PlexRequests.UI.Modules
|
||||||
}
|
}
|
||||||
form.PlexAuthToken = Session[SessionKeys.UserWizardPlexAuth].ToString(); // Set the auth token from the previous form
|
form.PlexAuthToken = Session[SessionKeys.UserWizardPlexAuth].ToString(); // Set the auth token from the previous form
|
||||||
|
|
||||||
|
// Get the machine ID from the settings (This could have changed)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var servers = PlexApi.GetServer(form.PlexAuthToken);
|
||||||
|
var firstServer = servers.Server.FirstOrDefault(x => x.AccessToken == form.PlexAuthToken);
|
||||||
|
|
||||||
|
Session[SessionKeys.UserWizardMachineId] = firstServer?.MachineIdentifier;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Probably bad settings, just continue
|
||||||
|
Log.Error(e);
|
||||||
|
}
|
||||||
|
|
||||||
var result = await PlexSettings.SaveSettingsAsync(form);
|
var result = await PlexSettings.SaveSettingsAsync(form);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
|
|
|
@ -440,4 +440,7 @@
|
||||||
<data name="Requests_ReleaseDate_Unavailable" xml:space="preserve">
|
<data name="Requests_ReleaseDate_Unavailable" xml:space="preserve">
|
||||||
<value>There is no information available for the release date</value>
|
<value>There is no information available for the release date</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Search_ViewInPlex" xml:space="preserve">
|
||||||
|
<value>View In Plex</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
9
PlexRequests.UI/Resources/UI1.Designer.cs
generated
9
PlexRequests.UI/Resources/UI1.Designer.cs
generated
|
@ -987,6 +987,15 @@ namespace PlexRequests.UI.Resources {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to View In Plex.
|
||||||
|
/// </summary>
|
||||||
|
public static string Search_ViewInPlex {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Search_ViewInPlex", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to You have reached your weekly request limit for Albums! Please contact your admin..
|
/// Looks up a localized string similar to You have reached your weekly request limit for Albums! Please contact your admin..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -175,6 +175,8 @@
|
||||||
{{#if_eq type "movie"}}
|
{{#if_eq type "movie"}}
|
||||||
{{#if_eq available true}}
|
{{#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>
|
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button>
|
||||||
|
<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}}
|
{{else}}
|
||||||
{{#if_eq requested true}}
|
{{#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>
|
<button style="text-align: right" class="btn btn-primary-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button>
|
||||||
|
@ -186,7 +188,8 @@
|
||||||
{{#if_eq type "tv"}}
|
{{#if_eq type "tv"}}
|
||||||
{{#if_eq tvFullyAvailable true}}
|
{{#if_eq tvFullyAvailable true}}
|
||||||
@*//TODO Not used yet*@
|
@*//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>
|
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button><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}}
|
{{else}}
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<button id="{{id}}" class="btn btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
<button id="{{id}}" class="btn btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||||
|
@ -259,7 +262,8 @@
|
||||||
<form method="POST" action="@url/search/request/{{type}}" id="form{{id}}">
|
<form method="POST" action="@url/search/request/{{type}}" id="form{{id}}">
|
||||||
<input name="{{type}}Id" type="text" value="{{id}}" hidden="hidden" />
|
<input name="{{type}}Id" type="text" value="{{id}}" hidden="hidden" />
|
||||||
{{#if_eq available true}}
|
{{#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>
|
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button><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}}
|
{{else}}
|
||||||
{{#if_eq requested true}}
|
{{#if_eq requested true}}
|
||||||
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button>
|
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue