mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-14 01:02:57 -07:00
Added a bunch of categories for tv search similar to what we have for movies.
This commit is contained in:
parent
7cbea541ce
commit
9886c40499
14 changed files with 641 additions and 249 deletions
16
Ombi.Api.Interfaces/ITraktApi.cs
Normal file
16
Ombi.Api.Interfaces/ITraktApi.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TraktApiSharp.Enums;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows.Common;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Interfaces
|
||||||
|
{
|
||||||
|
public interface ITraktApi
|
||||||
|
{
|
||||||
|
Task<IEnumerable<TraktMostAnticipatedShow>> GetAnticipatedShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
|
Task<IEnumerable<TraktMostWatchedShow>> GetMostWatchesShows(TraktTimePeriod period = null, int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
|
Task<IEnumerable<TraktShow>> GetPopularShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
|
Task<IEnumerable<TraktTrendingShow>> GetTrendingShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,10 @@
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
|
<HintPath>..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
@ -43,6 +47,10 @@
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="TraktApiSharp, Version=0.8.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="IApiRequest.cs" />
|
<Compile Include="IApiRequest.cs" />
|
||||||
|
@ -58,6 +66,7 @@
|
||||||
<Compile Include="IPushoverApi.cs" />
|
<Compile Include="IPushoverApi.cs" />
|
||||||
<Compile Include="ISickRageApi.cs" />
|
<Compile Include="ISickRageApi.cs" />
|
||||||
<Compile Include="ISonarrApi.cs" />
|
<Compile Include="ISonarrApi.cs" />
|
||||||
|
<Compile Include="ITraktApi.cs" />
|
||||||
<Compile Include="IWatcherApi.cs" />
|
<Compile Include="IWatcherApi.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
|
||||||
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
||||||
|
<package id="TraktApiSharp" version="0.8.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
|
@ -66,12 +66,17 @@
|
||||||
<HintPath>..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll</HintPath>
|
<HintPath>..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="TraktApiSharp, Version=0.8.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ApiRequest.cs" />
|
<Compile Include="ApiRequest.cs" />
|
||||||
<Compile Include="DiscordApi.cs" />
|
<Compile Include="DiscordApi.cs" />
|
||||||
<Compile Include="NetflixRouletteApi.cs" />
|
<Compile Include="NetflixRouletteApi.cs" />
|
||||||
<Compile Include="RadarrApi.cs" />
|
<Compile Include="RadarrApi.cs" />
|
||||||
|
<Compile Include="TraktApi.cs" />
|
||||||
<Compile Include="WatcherApi.cs" />
|
<Compile Include="WatcherApi.cs" />
|
||||||
<Compile Include="MusicBrainzApi.cs" />
|
<Compile Include="MusicBrainzApi.cs" />
|
||||||
<Compile Include="SlackApi.cs" />
|
<Compile Include="SlackApi.cs" />
|
||||||
|
|
51
Ombi.Api/TraktApi.cs
Normal file
51
Ombi.Api/TraktApi.cs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Interfaces;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using TraktApiSharp;
|
||||||
|
using TraktApiSharp.Enums;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows.Common;
|
||||||
|
using TraktApiSharp.Requests.Params;
|
||||||
|
|
||||||
|
namespace Ombi.Api
|
||||||
|
{
|
||||||
|
public class TraktApi : ITraktApi
|
||||||
|
{
|
||||||
|
private TraktClient Client { get; }
|
||||||
|
|
||||||
|
private static readonly string Encrypted = "z/56wM/oEkkCWEvSIZCrzQyUvvqmafQ3njqf0UNK5xuKbNYh5Wz8ocoG2QDa5y1DBkozLaKsGxORmAB1XUvwbnom8DVNo9gE++9GTuwxmGlLDD318PXpRmYmpKqNwFSKRZgF6ewiY9qR4t3iG0pGQwPA08FK3+H7kpOKAGJNR9RMDP9wwB6Vl4DuOiZb9/DETjzZ+/zId0ZqimrbN+PLrg==";
|
||||||
|
private readonly string _apiKey = StringCipher.Decrypt(Encrypted, "ApiKey");
|
||||||
|
public TraktApi()
|
||||||
|
{
|
||||||
|
Client = new TraktClient(_apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TraktShow>> GetPopularShows(int? page = null, int? limitPerPage = null)
|
||||||
|
{
|
||||||
|
var popular = await Client.Shows.GetPopularShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
|
return popular.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TraktTrendingShow>> GetTrendingShows(int? page = null, int? limitPerPage = null)
|
||||||
|
{
|
||||||
|
var trendingShowsTop10 = await Client.Shows.GetTrendingShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
|
return trendingShowsTop10.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TraktMostAnticipatedShow>> GetAnticipatedShows(int? page = null, int? limitPerPage = null)
|
||||||
|
{
|
||||||
|
var anticipatedShows = await Client.Shows.GetMostAnticipatedShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
|
return anticipatedShows.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TraktMostWatchedShow>> GetMostWatchesShows(TraktTimePeriod period = null, int? page = null, int? limitPerPage = null)
|
||||||
|
{
|
||||||
|
var anticipatedShows = await Client.Shows.GetMostWatchedShowsAsync(period ?? TraktTimePeriod.Monthly, new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
|
return anticipatedShows.Items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,4 +8,5 @@
|
||||||
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
||||||
<package id="System.Net.Http" version="4.0.0" targetFramework="net45" />
|
<package id="System.Net.Http" version="4.0.0" targetFramework="net45" />
|
||||||
<package id="TMDbLib" version="0.9.0.0-alpha" targetFramework="net45" />
|
<package id="TMDbLib" version="0.9.0.0-alpha" targetFramework="net45" />
|
||||||
|
<package id="TraktApiSharp" version="0.8.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
|
@ -46,5 +46,12 @@ namespace Ombi.Helpers
|
||||||
dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime();
|
dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime();
|
||||||
return dtDateTime;
|
return dtDateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long ToJavascriptTimestamp(this DateTime input)
|
||||||
|
{
|
||||||
|
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
var time = input.Subtract(new TimeSpan(epoch.Ticks));
|
||||||
|
return (long)(time.Ticks / 10000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,25 @@ $(function () {
|
||||||
moviesInTheaters();
|
moviesInTheaters();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TV DropDown
|
||||||
|
$('#popularShows').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
popularShows();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#trendingShows').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
trendingTv();
|
||||||
|
});
|
||||||
|
$('#mostWatchedShows').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
mostwatchedTv();
|
||||||
|
});
|
||||||
|
$('#anticipatedShows').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
anticipatedTv();
|
||||||
|
});
|
||||||
|
|
||||||
// Type in TV search
|
// Type in TV search
|
||||||
$("#tvSearchContent").on("input", function () {
|
$("#tvSearchContent").on("input", function () {
|
||||||
if (searchTimer) {
|
if (searchTimer) {
|
||||||
|
@ -293,6 +312,23 @@ $(function () {
|
||||||
getMovies(url);
|
getMovies(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function popularShows() {
|
||||||
|
var url = createBaseUrl(base, '/search/tv/popular');
|
||||||
|
getTvShows(url, true);
|
||||||
|
}
|
||||||
|
function anticipatedTv() {
|
||||||
|
var url = createBaseUrl(base, '/search/tv/anticipated');
|
||||||
|
getTvShows(url, true);
|
||||||
|
}
|
||||||
|
function trendingTv() {
|
||||||
|
var url = createBaseUrl(base, '/search/tv/trending');
|
||||||
|
getTvShows(url, true);
|
||||||
|
}
|
||||||
|
function mostwatchedTv() {
|
||||||
|
var url = createBaseUrl(base, '/search/tv/mostwatched');
|
||||||
|
getTvShows(url, true);
|
||||||
|
}
|
||||||
|
|
||||||
function getMovies(url) {
|
function getMovies(url) {
|
||||||
resetMovies();
|
resetMovies();
|
||||||
|
|
||||||
|
@ -323,10 +359,10 @@ $(function () {
|
||||||
var query = $("#tvSearchContent").val();
|
var query = $("#tvSearchContent").val();
|
||||||
|
|
||||||
var url = createBaseUrl(base, '/search/tv/');
|
var url = createBaseUrl(base, '/search/tv/');
|
||||||
query ? getTvShows(url + query) : resetTvShows();
|
query ? getTvShows(url + query, false) : resetTvShows();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTvShows(url) {
|
function getTvShows(url, loadImage) {
|
||||||
resetTvShows();
|
resetTvShows();
|
||||||
|
|
||||||
$('#tvSearchButton').attr("class", "fa fa-spinner fa-spin");
|
$('#tvSearchButton').attr("class", "fa fa-spinner fa-spin");
|
||||||
|
@ -338,7 +374,9 @@ $(function () {
|
||||||
$("#tvList").append(html);
|
$("#tvList").append(html);
|
||||||
|
|
||||||
checkNetflix(context.title, context.id);
|
checkNetflix(context.title, context.id);
|
||||||
|
if (loadImage) {
|
||||||
|
getTvPoster(result.id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -406,6 +444,16 @@ $(function () {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getTvPoster(theTvDbId) {
|
||||||
|
|
||||||
|
var url = createBaseUrl(base, '/search/tv/poster/');
|
||||||
|
$.ajax(url + theTvDbId).success(function (result) {
|
||||||
|
if (result) {
|
||||||
|
$('#' + theTvDbId + "imgDiv").html(" <img class='img-responsive' src='" + result + "' width='150' alt='poster'>");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
function buildMovieContext(result) {
|
function buildMovieContext(result) {
|
||||||
var date = new Date(result.releaseDate);
|
var date = new Date(result.releaseDate);
|
||||||
var year = date.getFullYear();
|
var year = date.getFullYear();
|
||||||
|
@ -432,6 +480,7 @@ $(function () {
|
||||||
var date = new Date(result.firstAired);
|
var date = new Date(result.firstAired);
|
||||||
var year = date.getFullYear();
|
var year = date.getFullYear();
|
||||||
var context = {
|
var context = {
|
||||||
|
status : result.status,
|
||||||
posterPath: result.banner,
|
posterPath: result.banner,
|
||||||
id: result.id,
|
id: result.id,
|
||||||
title: result.seriesName,
|
title: result.seriesName,
|
||||||
|
@ -448,7 +497,9 @@ $(function () {
|
||||||
tvPartialAvailable: result.tvPartialAvailable,
|
tvPartialAvailable: result.tvPartialAvailable,
|
||||||
disableTvRequestsByEpisode: result.disableTvRequestsByEpisode,
|
disableTvRequestsByEpisode: result.disableTvRequestsByEpisode,
|
||||||
disableTvRequestsBySeason: result.disableTvRequestsBySeason,
|
disableTvRequestsBySeason: result.disableTvRequestsBySeason,
|
||||||
enableTvRequestsForOnlySeries: result.enableTvRequestsForOnlySeries
|
enableTvRequestsForOnlySeries: result.enableTvRequestsForOnlySeries,
|
||||||
|
trailer: result.trailer,
|
||||||
|
homepage: result.homepage
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
|
@ -58,5 +58,20 @@ namespace Ombi.UI.Models
|
||||||
public bool DisableTvRequestsByEpisode { get; set; }
|
public bool DisableTvRequestsByEpisode { get; set; }
|
||||||
public bool DisableTvRequestsBySeason { get; set; }
|
public bool DisableTvRequestsBySeason { get; set; }
|
||||||
public bool EnableTvRequestsForOnlySeries { get; set; }
|
public bool EnableTvRequestsForOnlySeries { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used from the Trakt API
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The trailer.
|
||||||
|
/// </value>
|
||||||
|
public string Trailer { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// This is used from the Trakt API
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The trailer.
|
||||||
|
/// </value>
|
||||||
|
public string Homepage { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -58,6 +58,7 @@ using Ombi.Store.Repository;
|
||||||
using Ombi.UI.Helpers;
|
using Ombi.UI.Helpers;
|
||||||
using Ombi.UI.Models;
|
using Ombi.UI.Models;
|
||||||
using TMDbLib.Objects.General;
|
using TMDbLib.Objects.General;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows;
|
||||||
using Action = Ombi.Helpers.Analytics.Action;
|
using Action = Ombi.Helpers.Analytics.Action;
|
||||||
using EpisodesModel = Ombi.Store.EpisodesModel;
|
using EpisodesModel = Ombi.Store.EpisodesModel;
|
||||||
using ISecurityExtensions = Ombi.Core.ISecurityExtensions;
|
using ISecurityExtensions = Ombi.Core.ISecurityExtensions;
|
||||||
|
@ -76,7 +77,7 @@ namespace Ombi.UI.Modules
|
||||||
ISettingsService<PlexSettings> plexService, ISettingsService<AuthenticationSettings> auth,
|
ISettingsService<PlexSettings> plexService, ISettingsService<AuthenticationSettings> auth,
|
||||||
IRepository<UsersToNotify> u, ISettingsService<EmailNotificationSettings> email,
|
IRepository<UsersToNotify> u, ISettingsService<EmailNotificationSettings> email,
|
||||||
IIssueService issue, IAnalytics a, IRepository<RequestLimit> rl, ITransientFaultQueue tfQueue, IRepository<PlexContent> content,
|
IIssueService issue, IAnalytics a, IRepository<RequestLimit> rl, ITransientFaultQueue tfQueue, IRepository<PlexContent> content,
|
||||||
ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher)
|
ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher, ITraktApi traktApi)
|
||||||
: base("search", prSettings, security)
|
: base("search", prSettings, security)
|
||||||
{
|
{
|
||||||
Auth = auth;
|
Auth = auth;
|
||||||
|
@ -109,6 +110,7 @@ namespace Ombi.UI.Modules
|
||||||
MovieSender = movieSender;
|
MovieSender = movieSender;
|
||||||
WatcherCacher = watcherCacher;
|
WatcherCacher = watcherCacher;
|
||||||
RadarrCacher = radarrCacher;
|
RadarrCacher = radarrCacher;
|
||||||
|
TraktApi = traktApi;
|
||||||
|
|
||||||
Get["SearchIndex", "/", true] = async (x, ct) => await RequestLoad();
|
Get["SearchIndex", "/", true] = async (x, ct) => await RequestLoad();
|
||||||
|
|
||||||
|
@ -120,6 +122,13 @@ namespace Ombi.UI.Modules
|
||||||
Get["movie/upcoming", true] = async (x, ct) => await UpcomingMovies();
|
Get["movie/upcoming", true] = async (x, ct) => await UpcomingMovies();
|
||||||
Get["movie/playing", true] = async (x, ct) => await CurrentlyPlayingMovies();
|
Get["movie/playing", true] = async (x, ct) => await CurrentlyPlayingMovies();
|
||||||
|
|
||||||
|
Get["tv/popular", true] = async (x, ct) => await ProcessShows(ShowSearchType.Popular);
|
||||||
|
Get["tv/trending", true] = async (x, ct) => await ProcessShows(ShowSearchType.Trending);
|
||||||
|
Get["tv/mostwatched", true] = async (x, ct) => await ProcessShows(ShowSearchType.MostWatched);
|
||||||
|
Get["tv/anticipated", true] = async (x, ct) => await ProcessShows(ShowSearchType.Anticipated);
|
||||||
|
|
||||||
|
Get["tv/poster/{id}"] = p => GetTvPoster((int)p.id);
|
||||||
|
|
||||||
Post["request/movie", true] = async (x, ct) => await RequestMovie((int)Request.Form.movieId);
|
Post["request/movie", true] = async (x, ct) => await RequestMovie((int)Request.Form.movieId);
|
||||||
Post["request/tv", true] =
|
Post["request/tv", true] =
|
||||||
async (x, ct) => await RequestTvShow((int)Request.Form.tvId, (string)Request.Form.seasons);
|
async (x, ct) => await RequestTvShow((int)Request.Form.tvId, (string)Request.Form.seasons);
|
||||||
|
@ -129,6 +138,7 @@ namespace Ombi.UI.Modules
|
||||||
Get["/seasons"] = x => GetSeasons();
|
Get["/seasons"] = x => GetSeasons();
|
||||||
Get["/episodes", true] = async (x, ct) => await GetEpisodes();
|
Get["/episodes", true] = async (x, ct) => await GetEpisodes();
|
||||||
}
|
}
|
||||||
|
private ITraktApi TraktApi { get; }
|
||||||
private IWatcherCacher WatcherCacher { get; }
|
private IWatcherCacher WatcherCacher { get; }
|
||||||
private IMovieSender MovieSender { get; }
|
private IMovieSender MovieSender { get; }
|
||||||
private IRepository<PlexContent> PlexContentRepository { get; }
|
private IRepository<PlexContent> PlexContentRepository { get; }
|
||||||
|
@ -190,6 +200,17 @@ namespace Ombi.UI.Modules
|
||||||
return await ProcessMovies(MovieSearchType.Search, searchTerm);
|
return await ProcessMovies(MovieSearchType.Search, searchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response GetTvPoster(int theTvDbId)
|
||||||
|
{
|
||||||
|
var result = TvApi.ShowLookupByTheTvDbId(theTvDbId);
|
||||||
|
|
||||||
|
var banner = result.image?.medium;
|
||||||
|
if (!string.IsNullOrEmpty(banner))
|
||||||
|
{
|
||||||
|
banner = banner.Replace("http", "https"); // Always use the Https banners
|
||||||
|
}
|
||||||
|
return banner;
|
||||||
|
}
|
||||||
private async Task<Response> ProcessMovies(MovieSearchType searchType, string searchTerm)
|
private async Task<Response> ProcessMovies(MovieSearchType searchType, string searchTerm)
|
||||||
{
|
{
|
||||||
List<MovieResult> apiMovies;
|
List<MovieResult> apiMovies;
|
||||||
|
@ -322,6 +343,186 @@ namespace Ombi.UI.Modules
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Response> ProcessShows(ShowSearchType type)
|
||||||
|
{
|
||||||
|
var shows = new List<SearchTvShowViewModel>();
|
||||||
|
var prSettings = await PrService.GetSettingsAsync();
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ShowSearchType.Popular:
|
||||||
|
Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Popular", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
|
var popularShows = await TraktApi.GetPopularShows();
|
||||||
|
|
||||||
|
foreach (var popularShow in popularShows)
|
||||||
|
{
|
||||||
|
var theTvDbId = int.Parse(popularShow.Ids.Tvdb.ToString());
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
FirstAired = popularShow.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"),
|
||||||
|
Id = theTvDbId,
|
||||||
|
ImdbId = popularShow.Ids.Imdb,
|
||||||
|
Network = popularShow.Network,
|
||||||
|
Overview = popularShow.Overview.RemoveHtml(),
|
||||||
|
Rating = popularShow.Rating.ToString(),
|
||||||
|
Runtime = popularShow.Runtime.ToString(),
|
||||||
|
SeriesName = popularShow.Title,
|
||||||
|
Status = popularShow.Status.DisplayName,
|
||||||
|
DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode,
|
||||||
|
DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason,
|
||||||
|
EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason),
|
||||||
|
Trailer = popularShow.Trailer,
|
||||||
|
Homepage = popularShow.Homepage
|
||||||
|
};
|
||||||
|
shows.Add(model);
|
||||||
|
}
|
||||||
|
shows = await MapToTvModel(shows, prSettings);
|
||||||
|
break;
|
||||||
|
case ShowSearchType.Anticipated:
|
||||||
|
Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Anticipated", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
|
var anticipated = await TraktApi.GetAnticipatedShows();
|
||||||
|
foreach (var anticipatedShow in anticipated)
|
||||||
|
{
|
||||||
|
var show = anticipatedShow.Show;
|
||||||
|
var theTvDbId = int.Parse(show.Ids.Tvdb.ToString());
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
FirstAired = show.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"),
|
||||||
|
Id = theTvDbId,
|
||||||
|
ImdbId = show.Ids.Imdb,
|
||||||
|
Network = show.Network ?? string.Empty,
|
||||||
|
Overview = show.Overview?.RemoveHtml() ?? string.Empty,
|
||||||
|
Rating = show.Rating.ToString(),
|
||||||
|
Runtime = show.Runtime.ToString(),
|
||||||
|
SeriesName = show.Title,
|
||||||
|
Status = show.Status?.DisplayName ?? string.Empty,
|
||||||
|
DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode,
|
||||||
|
DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason,
|
||||||
|
EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason),
|
||||||
|
Trailer = show.Trailer,
|
||||||
|
Homepage = show.Homepage
|
||||||
|
};
|
||||||
|
shows.Add(model);
|
||||||
|
}
|
||||||
|
shows = await MapToTvModel(shows, prSettings);
|
||||||
|
break;
|
||||||
|
case ShowSearchType.MostWatched:
|
||||||
|
Analytics.TrackEventAsync(Category.Search, Action.TvShow, "MostWatched", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
|
var mostWatched = await TraktApi.GetMostWatchesShows();
|
||||||
|
foreach (var watched in mostWatched)
|
||||||
|
{
|
||||||
|
var show = watched.Show;
|
||||||
|
var theTvDbId = int.Parse(show.Ids.Tvdb.ToString());
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
FirstAired = show.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"),
|
||||||
|
Id = theTvDbId,
|
||||||
|
ImdbId = show.Ids.Imdb,
|
||||||
|
Network = show.Network,
|
||||||
|
Overview = show.Overview.RemoveHtml(),
|
||||||
|
Rating = show.Rating.ToString(),
|
||||||
|
Runtime = show.Runtime.ToString(),
|
||||||
|
SeriesName = show.Title,
|
||||||
|
Status = show.Status.DisplayName,
|
||||||
|
DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode,
|
||||||
|
DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason,
|
||||||
|
EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason),
|
||||||
|
Trailer = show.Trailer,
|
||||||
|
Homepage = show.Homepage
|
||||||
|
};
|
||||||
|
shows.Add(model);
|
||||||
|
}
|
||||||
|
shows = await MapToTvModel(shows, prSettings);
|
||||||
|
break;
|
||||||
|
case ShowSearchType.Trending:
|
||||||
|
Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Trending", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
|
var trending = await TraktApi.GetTrendingShows();
|
||||||
|
foreach (var watched in trending)
|
||||||
|
{
|
||||||
|
var show = watched.Show;
|
||||||
|
var theTvDbId = int.Parse(show.Ids.Tvdb.ToString());
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
FirstAired = show.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"),
|
||||||
|
Id = theTvDbId,
|
||||||
|
ImdbId = show.Ids.Imdb,
|
||||||
|
Network = show.Network,
|
||||||
|
Overview = show.Overview.RemoveHtml(),
|
||||||
|
Rating = show.Rating.ToString(),
|
||||||
|
Runtime = show.Runtime.ToString(),
|
||||||
|
SeriesName = show.Title,
|
||||||
|
Status = show.Status.DisplayName,
|
||||||
|
DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode,
|
||||||
|
DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason,
|
||||||
|
EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason),
|
||||||
|
Trailer = show.Trailer,
|
||||||
|
Homepage = show.Homepage
|
||||||
|
};
|
||||||
|
shows.Add(model);
|
||||||
|
}
|
||||||
|
shows = await MapToTvModel(shows, prSettings);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Response.AsJson(shows);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<SearchTvShowViewModel>> MapToTvModel(List<SearchTvShowViewModel> shows, PlexRequestSettings prSettings)
|
||||||
|
{
|
||||||
|
|
||||||
|
var plexSettings = await PlexService.GetSettingsAsync();
|
||||||
|
|
||||||
|
var providerId = string.Empty;
|
||||||
|
// Get the requests
|
||||||
|
var allResults = await RequestService.GetAllAsync();
|
||||||
|
allResults = allResults.Where(x => x.Type == RequestType.TvShow);
|
||||||
|
var distinctResults = allResults.DistinctBy(x => x.ProviderId);
|
||||||
|
var dbTv = distinctResults.ToDictionary(x => x.ProviderId);
|
||||||
|
|
||||||
|
// Check the external applications
|
||||||
|
var sonarrCached = SonarrCacher.QueuedIds().ToList();
|
||||||
|
var sickRageCache = SickRageCacher.QueuedIds(); // consider just merging sonarr/sickrage arrays
|
||||||
|
var content = PlexContentRepository.GetAll();
|
||||||
|
var plexTvShows = Checker.GetPlexTvShows(content).ToList();
|
||||||
|
|
||||||
|
foreach (var show in shows)
|
||||||
|
{
|
||||||
|
if (plexSettings.AdvancedSearch)
|
||||||
|
{
|
||||||
|
providerId = show.Id.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
var plexShow = Checker.GetTvShow(plexTvShows.ToArray(), show.SeriesName, show.FirstAired?.Substring(0, 4),
|
||||||
|
providerId);
|
||||||
|
if (plexShow != null)
|
||||||
|
{
|
||||||
|
show.Available = true;
|
||||||
|
show.PlexUrl = plexShow.Url;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dbTv.ContainsKey(show.Id))
|
||||||
|
{
|
||||||
|
var dbt = dbTv[show.Id];
|
||||||
|
|
||||||
|
show.Requested = true;
|
||||||
|
show.Episodes = dbt.Episodes.ToList();
|
||||||
|
show.Approved = dbt.Approved;
|
||||||
|
}
|
||||||
|
if (sonarrCached.Select(x => x.TvdbId).Contains(show.Id) || sickRageCache.Contains(show.Id))
|
||||||
|
// compare to the sonarr/sickrage db
|
||||||
|
{
|
||||||
|
show.Requested = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shows;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<Response> SearchTvShow(string searchTerm)
|
private async Task<Response> SearchTvShow(string searchTerm)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -1401,5 +1602,13 @@ namespace Ombi.UI.Modules
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum ShowSearchType
|
||||||
|
{
|
||||||
|
Popular,
|
||||||
|
Anticipated,
|
||||||
|
MostWatched,
|
||||||
|
Trending
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ namespace Ombi.UI.NinjectModules
|
||||||
Bind<INetflixApi>().To<NetflixRouletteApi>();
|
Bind<INetflixApi>().To<NetflixRouletteApi>();
|
||||||
Bind<IDiscordApi>().To<DiscordApi>();
|
Bind<IDiscordApi>().To<DiscordApi>();
|
||||||
Bind<IRadarrApi>().To<RadarrApi>();
|
Bind<IRadarrApi>().To<RadarrApi>();
|
||||||
|
Bind<ITraktApi>().To<TraktApi>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -206,6 +206,10 @@
|
||||||
<HintPath>..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll</HintPath>
|
<HintPath>..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="TraktApiSharp, Version=0.8.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Authentication\CustomAuthenticationConfiguration.cs" />
|
<Compile Include="Authentication\CustomAuthenticationConfiguration.cs" />
|
||||||
|
|
|
@ -75,9 +75,20 @@
|
||||||
<!-- TV tab -->
|
<!-- TV tab -->
|
||||||
<div role="tabpanel" class="tab-pane" id="TvShowTab">
|
<div role="tabpanel" class="tab-pane" id="TvShowTab">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="tvSearchContent" type="text" class="form-control form-control-custom form-control-search">
|
<input id="tvSearchContent" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons">
|
||||||
<div class="input-group-addon">
|
<div class="input-group-addon">
|
||||||
<i id="tvSearchButton" class="fa fa-search"></i>
|
<div class="btn-group">
|
||||||
|
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||||
|
@UI.Search_Suggestions
|
||||||
|
<i class="fa fa-chevron-down"></i>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a id="popularShows" href="#">Popular Shows</a></li>
|
||||||
|
<li><a id="trendingShows" href="#">Trending Shows</a></li>
|
||||||
|
<li><a id="mostWatchedShows" href="#">Most Watched Shows</a></li>
|
||||||
|
<li><a id="anticipatedShows" href="#">Most Anticipated Shows</a></li>
|
||||||
|
</ul>
|
||||||
|
</div><i id="tvSearchButton" class="fa fa-search"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
@ -106,10 +117,10 @@
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<!-- Movie and TV Results template -->
|
<!-- 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 class="row">
|
||||||
<div class="col-sm-2">
|
<div id="{{id}}imgDiv" class="col-sm-2">
|
||||||
|
|
||||||
{{#if_eq type "movie"}}
|
{{#if_eq type "movie"}}
|
||||||
{{#if posterPath}}
|
{{#if posterPath}}
|
||||||
|
@ -134,6 +145,15 @@
|
||||||
<h4>{{title}} ({{year}})</h4>
|
<h4>{{title}} ({{year}})</h4>
|
||||||
</a>
|
</a>
|
||||||
{{/if_eq}}
|
{{/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 available}}
|
{{#if available}}
|
||||||
<span class="label label-success">@UI.Search_Available_on_plex</span>
|
<span class="label label-success">@UI.Search_Available_on_plex</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@ -230,11 +250,11 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<!-- Music Results template -->
|
<!-- Music Results template -->
|
||||||
<script id="music-template" type="text/x-handlebars-template">
|
<script id="music-template" type="text/x-handlebars-template">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div id="{{id}}imageDiv" class="col-sm-2">
|
<div id="{{id}}imageDiv" class="col-sm-2">
|
||||||
{{#if coverArtUrl}}
|
{{#if coverArtUrl}}
|
||||||
|
@ -277,9 +297,9 @@
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="modal fade" id="seasonsModal">
|
<div class="modal fade" id="seasonsModal">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
@ -297,9 +317,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade" id="episodesModal">
|
<div class="modal fade" id="episodesModal">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content col-md-12">
|
<div class="modal-content col-md-12">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
@ -319,10 +339,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="issuesModal">
|
<div class="modal fade" id="issuesModal">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
@ -343,27 +363,27 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script id="seasons-template" type="text/x-handlebars-template">
|
<script id="seasons-template" type="text/x-handlebars-template">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<input type="checkbox" class="selectedSeasons" id="{{id}}" name="{{id}}"><label for="{{id}}">@UI.Search_Season {{id}}</label>
|
<input type="checkbox" class="selectedSeasons" id="{{id}}" name="{{id}}"><label for="{{id}}">@UI.Search_Season {{id}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script id="seasonNumber-template" type="text/x-handlebars-template">
|
<script id="seasonNumber-template" type="text/x-handlebars-template">
|
||||||
|
|
||||||
<div id="seasonNumber{{seasonNumber}}" class="col-md-12">
|
<div id="seasonNumber{{seasonNumber}}" class="col-md-12">
|
||||||
<strong>@UI.Search_Season {{seasonNumber}}</strong>
|
<strong>@UI.Search_Season {{seasonNumber}}</strong>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<script id="episode-template" type="text/x-handlebars-template">
|
<script id="episode-template" type="text/x-handlebars-template">
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<div class="checkbox" style="margin-bottom:0px; margin-top:0px;">
|
<div class="checkbox" style="margin-bottom:0px; margin-top:0px;">
|
||||||
{{#if_eq requested true}}
|
{{#if_eq requested true}}
|
||||||
|
@ -374,6 +394,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@Html.LoadSearchAssets()
|
@Html.LoadSearchAssets()
|
||||||
|
|
|
@ -53,4 +53,5 @@
|
||||||
<package id="System.Runtime.Extensions" version="4.0.0" targetFramework="net45" />
|
<package id="System.Runtime.Extensions" version="4.0.0" targetFramework="net45" />
|
||||||
<package id="System.Text.RegularExpressions" version="4.0.0" targetFramework="net45" />
|
<package id="System.Text.RegularExpressions" version="4.0.0" targetFramework="net45" />
|
||||||
<package id="TMDbLib" version="0.9.0.0-alpha" targetFramework="net45" />
|
<package id="TMDbLib" version="0.9.0.0-alpha" targetFramework="net45" />
|
||||||
|
<package id="TraktApiSharp" version="0.8.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
Loading…
Add table
Add a link
Reference in a new issue