Additional movie information

pull/1011/head
Jamie.Rees 8 years ago
parent 1ddb6c7f01
commit 16c94f2414

@ -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\CouchPotatoProfiles.cs" />
<Compile Include="Movie\CouchPotatoStatus.cs" /> <Compile Include="Movie\CouchPotatoStatus.cs" />
<Compile Include="Movie\CouchPotatoApiKey.cs" /> <Compile Include="Movie\CouchPotatoApiKey.cs" />
<Compile Include="Movie\TmdbMovieDetails.cs" />
<Compile Include="Music\HeadphonesAlbumSearchResult.cs" /> <Compile Include="Music\HeadphonesAlbumSearchResult.cs" />
<Compile Include="Music\HeadphonesArtistSearchResult.cs" /> <Compile Include="Music\HeadphonesArtistSearchResult.cs" />
<Compile Include="Music\HeadphonesGetIndex.cs" /> <Compile Include="Music\HeadphonesGetIndex.cs" />

@ -32,6 +32,8 @@ namespace Ombi.Api
public abstract class MovieBase public abstract class MovieBase
{ {
private static readonly string Encrypted = "0T3QNSseexLO7n7UPiJvl70Y+KKnvbeTlsusl7Kwq0hPH0BHOuFNGwksNCjkwqWedyDdI/MJeUR4wtL4bIl0Z+//uHXEaYM/4H2pjeLbH5EWdUe5TTj1AhaIR5PQweamvcienRyFD/3YPCC/+qL5mHkKXBkPumMod3Zb/4yN0Ik="; 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,17 @@
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using NLog.Fluent;
using Ombi.Api.Models.Movie;
using RestSharp;
using TMDbLib.Client; using TMDbLib.Client;
using TMDbLib.Objects.General; using TMDbLib.Objects.General;
using TMDbLib.Objects.Movies; using TMDbLib.Objects.Movies;
using TMDbLib.Objects.Search; using TMDbLib.Objects.Search;
using Movie = TMDbLib.Objects.Movies.Movie;
namespace Ombi.Api namespace Ombi.Api
{ {
@ -39,9 +44,12 @@ namespace Ombi.Api
public TheMovieDbApi() public TheMovieDbApi()
{ {
Client = new TMDbClient(ApiKey); Client = new TMDbClient(ApiKey);
Api = new ApiRequest();
} }
private ApiRequest Api { get; }
public TMDbClient Client { get; set; } public TMDbClient Client { get; set; }
private const string BaseUrl = "https://api.themoviedb.org/3/";
public async Task<List<SearchMovie>> SearchMovie(string searchTerm) public async Task<List<SearchMovie>> SearchMovie(string searchTerm)
{ {
var results = await Client.SearchMovie(searchTerm); var results = await Client.SearchMovie(searchTerm);
@ -59,6 +67,26 @@ namespace Ombi.Api
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) public async Task<Movie> GetMovieInformation(int tmdbId)
{ {
var movies = await Client.GetMovie(tmdbId); var movies = await Client.GetMovie(tmdbId);

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

@ -266,17 +266,6 @@ namespace Ombi.UI.Modules
var counter = 0; var counter = 0;
foreach (var movie in apiMovies) 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 var viewMovie = new SearchMovieViewModel
{ {
Adult = movie.Adult, Adult = movie.Adult,
@ -294,6 +283,28 @@ namespace Ombi.UI.Modules
VoteAverage = movie.VoteAverage, VoteAverage = movie.VoteAverage,
VoteCount = movie.VoteCount 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 canSee = CanUserSeeThisRequest(viewMovie.Id, Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests), dbMovies);
var plexMovie = Checker.GetMovie(plexMovies.ToArray(), movie.Title, movie.ReleaseDate?.Year.ToString(), var plexMovie = Checker.GetMovie(plexMovies.ToArray(), movie.Title, movie.ReleaseDate?.Year.ToString(),
imdbId); imdbId);

@ -117,8 +117,161 @@
</div> </div>
} }
<!-- 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">
{{#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="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}}
<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>
<!-- Description -->
<p style="font-size:0.9rem !important">{{overview}}</p>
<br />
<br />
<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-template2" type="text/x-handlebars-template">
<div class="row"> <div class="row">
<div id="{{id}}imgDiv" class="col-sm-2"> <div id="{{id}}imgDiv" class="col-sm-2">

Loading…
Cancel
Save