2014-02-06 05:39:16 +01:00
using MediaBrowser.Controller.Entities ;
using MediaBrowser.Controller.Entities.Movies ;
2014-11-18 03:48:22 +01:00
using MediaBrowser.Controller.Library ;
2014-02-06 05:39:16 +01:00
using MediaBrowser.Controller.Providers ;
using MediaBrowser.Model.Entities ;
using MediaBrowser.Model.Logging ;
using MediaBrowser.Model.Serialization ;
using System ;
using System.Collections.Generic ;
using System.Globalization ;
using System.IO ;
using System.Linq ;
using System.Net ;
using System.Threading ;
using System.Threading.Tasks ;
2015-10-04 06:23:11 +02:00
using CommonIO ;
2014-02-06 05:39:16 +01:00
namespace MediaBrowser.Providers.Movies
{
public class GenericMovieDbInfo < T >
2015-03-14 21:00:32 +01:00
where T : BaseItem , new ( )
2014-02-06 05:39:16 +01:00
{
private readonly ILogger _logger ;
private readonly IJsonSerializer _jsonSerializer ;
2014-11-18 03:48:22 +01:00
private readonly ILibraryManager _libraryManager ;
2015-09-13 23:32:02 +02:00
private readonly IFileSystem _fileSystem ;
2014-02-06 05:39:16 +01:00
private readonly CultureInfo _usCulture = new CultureInfo ( "en-US" ) ;
2015-09-13 23:32:02 +02:00
public GenericMovieDbInfo ( ILogger logger , IJsonSerializer jsonSerializer , ILibraryManager libraryManager , IFileSystem fileSystem )
2014-02-06 05:39:16 +01:00
{
_logger = logger ;
_jsonSerializer = jsonSerializer ;
2014-11-18 03:48:22 +01:00
_libraryManager = libraryManager ;
2015-09-13 23:32:02 +02:00
_fileSystem = fileSystem ;
2014-02-06 05:39:16 +01:00
}
2014-02-07 04:10:13 +01:00
public async Task < MetadataResult < T > > GetMetadata ( ItemLookupInfo itemId , CancellationToken cancellationToken )
2014-02-06 05:39:16 +01:00
{
var tmdbId = itemId . GetProviderId ( MetadataProviders . Tmdb ) ;
var imdbId = itemId . GetProviderId ( MetadataProviders . Imdb ) ;
// Don't search for music video id's because it is very easy to misidentify.
if ( string . IsNullOrEmpty ( tmdbId ) & & string . IsNullOrEmpty ( imdbId ) & & typeof ( T ) ! = typeof ( MusicVideo ) )
{
2014-11-18 03:48:22 +01:00
var searchResults = await new MovieDbSearch ( _logger , _jsonSerializer , _libraryManager ) . GetMovieSearchResults ( itemId , cancellationToken ) . ConfigureAwait ( false ) ;
2014-03-01 23:34:27 +01:00
var searchResult = searchResults . FirstOrDefault ( ) ;
2014-02-15 17:36:09 +01:00
if ( searchResult ! = null )
{
2014-03-02 18:09:35 +01:00
tmdbId = searchResult . GetProviderId ( MetadataProviders . Tmdb ) ;
2014-02-15 17:36:09 +01:00
}
2014-02-06 05:39:16 +01:00
}
if ( ! string . IsNullOrEmpty ( tmdbId ) | | ! string . IsNullOrEmpty ( imdbId ) )
{
cancellationToken . ThrowIfCancellationRequested ( ) ;
2015-06-29 03:10:45 +02:00
return await FetchMovieData ( tmdbId , imdbId , itemId . MetadataLanguage , itemId . MetadataCountryCode , cancellationToken ) . ConfigureAwait ( false ) ;
2014-02-06 05:39:16 +01:00
}
2015-06-29 03:10:45 +02:00
return new MetadataResult < T > ( ) ;
2014-02-06 05:39:16 +01:00
}
/// <summary>
/// Fetches the movie data.
/// </summary>
/// <param name="tmdbId">The TMDB identifier.</param>
/// <param name="imdbId">The imdb identifier.</param>
/// <param name="language">The language.</param>
/// <param name="preferredCountryCode">The preferred country code.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{`0}.</returns>
2015-06-29 03:10:45 +02:00
private async Task < MetadataResult < T > > FetchMovieData ( string tmdbId , string imdbId , string language , string preferredCountryCode , CancellationToken cancellationToken )
2014-02-06 05:39:16 +01:00
{
2015-06-29 03:10:45 +02:00
var item = new MetadataResult < T >
{
Item = new T ( )
} ;
2014-02-06 05:39:16 +01:00
string dataFilePath = null ;
MovieDbProvider . CompleteMovieData movieInfo = null ;
// Id could be ImdbId or TmdbId
if ( string . IsNullOrEmpty ( tmdbId ) )
{
2014-09-28 22:49:43 +02:00
movieInfo = await MovieDbProvider . Current . FetchMainResult ( imdbId , false , language , cancellationToken ) . ConfigureAwait ( false ) ;
2015-10-26 06:29:32 +01:00
if ( movieInfo ! = null )
{
tmdbId = movieInfo . id . ToString ( _usCulture ) ;
2014-02-06 05:39:16 +01:00
2015-10-26 06:29:32 +01:00
dataFilePath = MovieDbProvider . Current . GetDataFilePath ( tmdbId , language ) ;
_fileSystem . CreateDirectory ( Path . GetDirectoryName ( dataFilePath ) ) ;
_jsonSerializer . SerializeToFile ( movieInfo , dataFilePath ) ;
}
2014-02-06 05:39:16 +01:00
}
2015-10-26 06:29:32 +01:00
if ( ! string . IsNullOrWhiteSpace ( tmdbId ) )
{
await MovieDbProvider . Current . EnsureMovieInfo ( tmdbId , language , cancellationToken ) . ConfigureAwait ( false ) ;
2014-02-06 05:39:16 +01:00
2015-10-26 06:29:32 +01:00
dataFilePath = dataFilePath ? ? MovieDbProvider . Current . GetDataFilePath ( tmdbId , language ) ;
movieInfo = movieInfo ? ? _jsonSerializer . DeserializeFromFile < MovieDbProvider . CompleteMovieData > ( dataFilePath ) ;
2014-02-06 05:39:16 +01:00
2016-01-21 19:50:43 +01:00
var settings = await MovieDbProvider . Current . GetTmdbSettings ( cancellationToken ) . ConfigureAwait ( false ) ;
ProcessMainInfo ( item , settings , preferredCountryCode , movieInfo ) ;
2015-10-26 06:29:32 +01:00
item . HasMetadata = true ;
}
2014-02-06 05:39:16 +01:00
return item ;
}
/// <summary>
/// Processes the main info.
/// </summary>
2015-06-29 03:10:45 +02:00
/// <param name="resultItem">The result item.</param>
2016-01-21 19:50:43 +01:00
/// <param name="settings">The settings.</param>
2014-02-06 05:39:16 +01:00
/// <param name="preferredCountryCode">The preferred country code.</param>
/// <param name="movieData">The movie data.</param>
2016-01-21 19:50:43 +01:00
private void ProcessMainInfo ( MetadataResult < T > resultItem , TmdbSettingsResult settings , string preferredCountryCode , MovieDbProvider . CompleteMovieData movieData )
2014-02-06 05:39:16 +01:00
{
2015-06-29 03:10:45 +02:00
var movie = resultItem . Item ;
2015-03-10 02:30:20 +01:00
movie . Name = movieData . GetTitle ( ) ? ? movie . Name ;
var hasOriginalTitle = movie as IHasOriginalTitle ;
if ( hasOriginalTitle ! = null )
{
hasOriginalTitle . OriginalTitle = movieData . GetOriginalTitle ( ) ;
}
2014-02-06 05:39:16 +01:00
// Bug in Mono: WebUtility.HtmlDecode should return null if the string is null but in Mono it generate an System.ArgumentNullException.
movie . Overview = movieData . overview ! = null ? WebUtility . HtmlDecode ( movieData . overview ) : null ;
movie . Overview = movie . Overview ! = null ? movie . Overview . Replace ( "\n\n" , "\n" ) : null ;
movie . HomePageUrl = movieData . homepage ;
var hasBudget = movie as IHasBudget ;
if ( hasBudget ! = null )
{
hasBudget . Budget = movieData . budget ;
hasBudget . Revenue = movieData . revenue ;
}
if ( ! string . IsNullOrEmpty ( movieData . tagline ) )
{
var hasTagline = movie as IHasTaglines ;
if ( hasTagline ! = null )
{
hasTagline . Taglines . Clear ( ) ;
hasTagline . AddTagline ( movieData . tagline ) ;
}
}
2014-05-16 21:16:29 +02:00
if ( movieData . production_countries ! = null )
{
var hasProductionLocations = movie as IHasProductionLocations ;
if ( hasProductionLocations ! = null )
{
hasProductionLocations . ProductionLocations = movieData
. production_countries
. Select ( i = > i . name )
. ToList ( ) ;
}
}
2014-02-06 05:39:16 +01:00
movie . SetProviderId ( MetadataProviders . Tmdb , movieData . id . ToString ( _usCulture ) ) ;
movie . SetProviderId ( MetadataProviders . Imdb , movieData . imdb_id ) ;
if ( movieData . belongs_to_collection ! = null )
{
movie . SetProviderId ( MetadataProviders . TmdbCollection ,
movieData . belongs_to_collection . id . ToString ( CultureInfo . InvariantCulture ) ) ;
var movieItem = movie as Movie ;
if ( movieItem ! = null )
{
2016-03-14 02:34:24 +01:00
movieItem . CollectionName = movieData . belongs_to_collection . name ;
2014-02-06 05:39:16 +01:00
}
}
float rating ;
string voteAvg = movieData . vote_average . ToString ( CultureInfo . InvariantCulture ) ;
if ( float . TryParse ( voteAvg , NumberStyles . AllowDecimalPoint , CultureInfo . InvariantCulture , out rating ) )
{
movie . CommunityRating = rating ;
}
movie . VoteCount = movieData . vote_count ;
//release date and certification are retrieved based on configured country and we fall back on US if not there and to minimun release date if still no match
if ( movieData . releases ! = null & & movieData . releases . countries ! = null )
{
2015-08-19 18:43:23 +02:00
var releases = movieData . releases . countries . Where ( i = > ! string . IsNullOrWhiteSpace ( i . certification ) ) . ToList ( ) ;
var ourRelease = releases . FirstOrDefault ( c = > c . iso_3166_1 . Equals ( preferredCountryCode , StringComparison . OrdinalIgnoreCase ) ) ;
var usRelease = releases . FirstOrDefault ( c = > c . iso_3166_1 . Equals ( "US" , StringComparison . OrdinalIgnoreCase ) ) ;
var minimunRelease = releases . OrderBy ( c = > c . release_date ) . FirstOrDefault ( ) ;
if ( ourRelease ! = null )
{
var ratingPrefix = string . Equals ( preferredCountryCode , "us" , StringComparison . OrdinalIgnoreCase ) ? "" : preferredCountryCode + "-" ;
movie . OfficialRating = ratingPrefix + ourRelease . certification ;
}
else if ( usRelease ! = null )
{
movie . OfficialRating = usRelease . certification ;
}
else if ( minimunRelease ! = null )
{
movie . OfficialRating = minimunRelease . iso_3166_1 + "-" + minimunRelease . certification ;
}
2014-02-06 05:39:16 +01:00
}
2014-03-02 19:01:46 +01:00
if ( ! string . IsNullOrWhiteSpace ( movieData . release_date ) )
2014-02-06 05:39:16 +01:00
{
2014-03-02 19:01:46 +01:00
DateTime r ;
// These dates are always in this exact format
if ( DateTime . TryParse ( movieData . release_date , _usCulture , DateTimeStyles . None , out r ) )
{
movie . PremiereDate = r . ToUniversalTime ( ) ;
movie . ProductionYear = movie . PremiereDate . Value . Year ;
}
2014-02-06 05:39:16 +01:00
}
//studios
if ( movieData . production_companies ! = null )
{
movie . Studios . Clear ( ) ;
foreach ( var studio in movieData . production_companies . Select ( c = > c . name ) )
{
movie . AddStudio ( studio ) ;
}
}
// genres
// Movies get this from imdb
var genres = movieData . genres ? ? new List < MovieDbProvider . GenreItem > ( ) ;
foreach ( var genre in genres . Select ( g = > g . name ) )
{
movie . AddGenre ( genre ) ;
}
2015-07-24 04:48:10 +02:00
resultItem . ResetPeople ( ) ;
2016-04-29 10:06:41 +02:00
var tmdbImageUrl = settings . images . secure_base_url + "original" ;
2015-08-19 18:43:23 +02:00
2014-02-06 05:39:16 +01:00
//Actors, Directors, Writers - all in People
//actors come from cast
if ( movieData . casts ! = null & & movieData . casts . cast ! = null )
{
2015-06-28 18:36:25 +02:00
foreach ( var actor in movieData . casts . cast . OrderBy ( a = > a . order ) )
{
2016-01-21 19:50:43 +01:00
var personInfo = new PersonInfo
{
Name = actor . name . Trim ( ) ,
Role = actor . character ,
Type = PersonType . Actor ,
SortOrder = actor . order
} ;
if ( ! string . IsNullOrWhiteSpace ( actor . profile_path ) )
{
personInfo . ImageUrl = tmdbImageUrl + actor . profile_path ;
}
if ( actor . id > 0 )
{
personInfo . SetProviderId ( MetadataProviders . Tmdb , actor . id . ToString ( CultureInfo . InvariantCulture ) ) ;
}
resultItem . AddPerson ( personInfo ) ;
2015-06-28 18:36:25 +02:00
}
2014-02-06 05:39:16 +01:00
}
//and the rest from crew
if ( movieData . casts ! = null & & movieData . casts . crew ! = null )
{
2015-06-28 18:36:25 +02:00
foreach ( var person in movieData . casts . crew )
{
2015-09-25 14:53:38 +02:00
// Normalize this
var type = person . department ;
if ( string . Equals ( type , "writing" , StringComparison . OrdinalIgnoreCase ) )
{
type = PersonType . Writer ;
}
2016-01-21 19:50:43 +01:00
var personInfo = new PersonInfo
{
Name = person . name . Trim ( ) ,
Role = person . job ,
Type = type
} ;
if ( ! string . IsNullOrWhiteSpace ( person . profile_path ) )
{
personInfo . ImageUrl = tmdbImageUrl + person . profile_path ;
}
if ( person . id > 0 )
{
personInfo . SetProviderId ( MetadataProviders . Tmdb , person . id . ToString ( CultureInfo . InvariantCulture ) ) ;
}
resultItem . AddPerson ( personInfo ) ;
2015-06-28 18:36:25 +02:00
}
2014-02-06 05:39:16 +01:00
}
if ( movieData . keywords ! = null & & movieData . keywords . keywords ! = null )
{
2016-05-31 20:07:54 +02:00
movie . Keywords = movieData . keywords . keywords . Select ( i = > i . name ) . ToList ( ) ;
2014-02-06 05:39:16 +01:00
}
if ( movieData . trailers ! = null & & movieData . trailers . youtube ! = null & &
movieData . trailers . youtube . Count > 0 )
{
var hasTrailers = movie as IHasTrailers ;
if ( hasTrailers ! = null )
{
hasTrailers . RemoteTrailers = movieData . trailers . youtube . Select ( i = > new MediaUrl
{
2016-04-21 07:13:33 +02:00
Url = string . Format ( "https://www.youtube.com/watch?v={0}" , i . source ) ,
2016-06-17 15:06:13 +02:00
Name = i . name
2014-02-06 05:39:16 +01:00
} ) . ToList ( ) ;
}
}
}
}
}