From 761b82dbff36ce663f2cc1d3c4b57bbec2503053 Mon Sep 17 00:00:00 2001 From: reven Date: Mon, 22 Nov 2021 22:38:45 +1300 Subject: [PATCH] added MetaNodes plugin --- .gitignore | 3 + BasicNodes/BasicNodes.csproj | Bin 2042 -> 2140 bytes BasicNodes/File/MoveFile.cs | 48 +--- Builds/BasicNodes.zip | Bin 26963 -> 26606 bytes Builds/MetaNodes.zip | Bin 0 -> 71266 bytes Builds/VideoNodes.zip | Bin 35111 -> 35304 bytes FileFlowsPlugins.sln | 23 +- MetaNodes/Globals.cs | 7 + MetaNodes/MetaNodes.csproj | Bin 0 -> 2052 bytes MetaNodes/MetaNodes.en.json | 24 ++ MetaNodes/Plugin.cs | 11 + MetaNodes/Tests/TestLogger.cs | 43 ++++ .../Tests/TheMovieDb/MovieLookupTests.cs | 115 ++++++++++ .../Tests/TheMovieDb/MovieRenamerTests.cs | 134 +++++++++++ MetaNodes/TheMovieDb/MovieLookup.cs | 105 +++++++++ MetaNodes/TheMovieDb/MovieRenamer.cs | 80 +++++++ .../ApiRequest/ApiRequestBase.cs | 165 +++++++++++++ .../ApiRequest/IApiRequest.cs | 8 + .../ApiRequest/IsoDateTimeConverterEx.cs | 56 +++++ .../TheMovieDbWrapper/ApiResponse/ApiError.cs | 33 +++ .../ApiResponse/ApiQueryResponse.cs | 17 ++ .../ApiResponse/ApiResponseBase.cs | 26 +++ .../ApiResponse/ApiSearchResponse.cs | 42 ++++ .../ApiResponse/TmdbStatusCode.cs | 217 ++++++++++++++++++ .../TheMovieDbWrapper/IApiSettings.cs | 9 + .../TheMovieDbWrapper/IMovieDbApi.cs | 58 +++++ .../ThirdParty/TheMovieDbWrapper/LICENSE | 21 ++ .../Certifications/ApiMovieRatingRequest.cs | 53 +++++ .../Certifications/IApiMovieRatingRequest.cs | 17 ++ .../MovieDb/Certifications/MovieRatings.cs | 62 +++++ .../MovieDb/Collections/CollectionInfo.cs | 30 +++ .../MovieDb/Companies/ApiCompanyRequest.cs | 52 +++++ .../MovieDb/Companies/IApiCompanyRequest.cs | 28 +++ .../MovieDb/Companies/ParentCompany.cs | 27 +++ .../MovieDb/Companies/ProductionCompany.cs | 32 +++ .../Companies/ProductionCompanyInfo.cs | 58 +++++ .../MovieDb/Configuration/ApiConfiguration.cs | 25 ++ .../Configuration/ApiConfigurationRequest.cs | 22 ++ .../Configuration/IApiConfigurationRequest.cs | 21 ++ .../Configuration/ImageConfiguration.cs | 40 ++++ .../TheMovieDbWrapper/MovieDb/Country.cs | 58 +++++ .../MovieDb/Genres/ApiGenreRequest.cs | 155 +++++++++++++ .../TheMovieDbWrapper/MovieDb/Genres/Genre.cs | 51 ++++ .../MovieDb/Genres/GenreFactory.cs | 110 +++++++++ .../GenreIdCollectionMappingExtensions.cs | 61 +++++ .../MovieDb/Genres/IApiGenreRequest.cs | 64 ++++++ .../ApiProfessionRequest.cs | 38 +++ .../IApiProfessionRequest.cs | 18 ++ .../MovieDb/IndustryProfessions/Profession.cs | 18 ++ .../MovieDb/Keywords/Keyword.cs | 57 +++++ .../MovieDb/Keywords/KeywordConverter.cs | 43 ++++ .../TheMovieDbWrapper/MovieDb/Language.cs | 58 +++++ .../MovieDb/Movies/ApiMovieRequest.cs | 160 +++++++++++++ .../MovieDb/Movies/IApiMovieRequest.cs | 68 ++++++ .../TheMovieDbWrapper/MovieDb/Movies/Movie.cs | 109 +++++++++ .../MovieDb/Movies/MovieCredit.cs | 71 ++++++ .../MovieDb/Movies/MovieInfo.cs | 61 +++++ .../MovieDb/People/ApiPeopleRequest.cs | 86 +++++++ .../MovieDb/People/Gender.cs | 9 + .../MovieDb/People/IApiPeopleRequest.cs | 41 ++++ .../MovieDb/People/Person.cs | 57 +++++ .../MovieDb/People/PersonInfo.cs | 146 ++++++++++++ .../MovieDb/People/PersonMovieCredit.cs | 84 +++++++ .../MovieDb/People/PersonTVCredit.cs | 84 +++++++ .../MovieDb/TV/ApiTVShowRequest.cs | 115 ++++++++++ .../MovieDb/TV/IApiTVShowRequest.cs | 47 ++++ .../TheMovieDbWrapper/MovieDb/TV/Network.cs | 51 ++++ .../TheMovieDbWrapper/MovieDb/TV/Season.cs | 36 +++ .../TheMovieDbWrapper/MovieDb/TV/TVShow.cs | 100 ++++++++ .../MovieDb/TV/TVShowCreator.cs | 55 +++++ .../MovieDb/TV/TVShowInfo.cs | 63 +++++ .../TheMovieDbWrapper/MovieDbFactory.cs | 203 ++++++++++++++++ .../Shims/CollectionExtensions.cs | 13 ++ .../Shims/ImportingConstructorAttribute.cs | 8 + MetaNodes/ThirdParty/TheMovieDbWrapper/info | 7 + Plugin.deps.json | 23 -- Plugin.pdb | Bin 13984 -> 14372 bytes VideoNodes/VideoNodes.csproj | Bin 1518 -> 1502 bytes plugins.json | 9 +- 79 files changed, 4079 insertions(+), 70 deletions(-) create mode 100644 Builds/MetaNodes.zip create mode 100644 MetaNodes/Globals.cs create mode 100644 MetaNodes/MetaNodes.csproj create mode 100644 MetaNodes/MetaNodes.en.json create mode 100644 MetaNodes/Plugin.cs create mode 100644 MetaNodes/Tests/TestLogger.cs create mode 100644 MetaNodes/Tests/TheMovieDb/MovieLookupTests.cs create mode 100644 MetaNodes/Tests/TheMovieDb/MovieRenamerTests.cs create mode 100644 MetaNodes/TheMovieDb/MovieLookup.cs create mode 100644 MetaNodes/TheMovieDb/MovieRenamer.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/ApiRequestBase.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/IApiRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/IsoDateTimeConverterEx.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiError.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiQueryResponse.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiResponseBase.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiSearchResponse.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/TmdbStatusCode.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/IApiSettings.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/IMovieDbApi.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/LICENSE create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/ApiMovieRatingRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/IApiMovieRatingRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/MovieRatings.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Collections/CollectionInfo.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ApiCompanyRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/IApiCompanyRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ParentCompany.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ProductionCompany.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ProductionCompanyInfo.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ApiConfiguration.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ApiConfigurationRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/IApiConfigurationRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ImageConfiguration.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Country.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/ApiGenreRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/Genre.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/GenreFactory.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/GenreIdCollectionMappingExtensions.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/IApiGenreRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/ApiProfessionRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/IApiProfessionRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/Profession.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Keywords/Keyword.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Keywords/KeywordConverter.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Language.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/ApiMovieRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/IApiMovieRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/Movie.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/MovieCredit.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/MovieInfo.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/ApiPeopleRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/Gender.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/IApiPeopleRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/Person.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonInfo.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonMovieCredit.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonTVCredit.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/ApiTVShowRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/IApiTVShowRequest.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/Network.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/Season.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShow.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShowCreator.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShowInfo.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDbFactory.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/Shims/CollectionExtensions.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/Shims/ImportingConstructorAttribute.cs create mode 100644 MetaNodes/ThirdParty/TheMovieDbWrapper/info delete mode 100644 Plugin.deps.json diff --git a/.gitignore b/.gitignore index 1937c802..62376d51 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ Plugin.dll */.vs *.suo TestStore/ +.vs/FileFlowsPlugins/v17/.futdcache.v1 +.vs/FileFlowsPlugins/DesignTimeBuild/.dtbcache.v2 +.vs/FileFlowsPlugins/project-colors.json diff --git a/BasicNodes/BasicNodes.csproj b/BasicNodes/BasicNodes.csproj index b2b130ce4d2fc083a879675806ef9985e214fd85..234feee3205778b60795375cb07501cd0d8ac73f 100644 GIT binary patch delta 135 zcmeyxe@9@$3r0rE$uAj0fuuc?|HK07xlo%NmHeY1s JWd=&i001275!C + if (DeleteOriginal && original != args.FileName) { try { - if (System.IO.File.Exists(dest)) - System.IO.File.Delete(dest); - args.Logger.ILog($"Moving file: \"{args.WorkingFile}\" to \"{dest}\""); - System.IO.File.Move(args.WorkingFile, dest, true); - - if (DeleteOriginal && args.WorkingFile != args.FileName) - { - System.IO.File.Delete(args.FileName); - } - args.SetWorkingFile(dest); - - moved = true; - } - catch (Exception ex) + System.IO.File.Delete(original); + }catch(Exception ex) { - args.Logger.ELog("Failed to move file: " + ex.Message); + args.Logger?.WLog("Failed to delete original file: " + ex.Message); } - }); - - while (task.IsCompleted == false) - { - long currentSize = 0; - var destFileInfo = new FileInfo(dest); - if (destFileInfo.Exists) - currentSize = destFileInfo.Length; - - args.PartPercentageUpdate(currentSize / fileSize * 100); - System.Threading.Thread.Sleep(50); } - - if (moved == false) - return -1; - - args.PartPercentageUpdate(100); - - return base.Execute(args); + return 1; } } } \ No newline at end of file diff --git a/Builds/BasicNodes.zip b/Builds/BasicNodes.zip index bd2f7afda245f8b17d296480dda7fb71ddcea2ed..ab046b5e58009411322e57c21c80ca349e350967 100644 GIT binary patch delta 25514 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
T(rO%hgivyNxL-3>m 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℘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 literal 0 HcmV?d00001 diff --git a/MetaNodes/MetaNodes.en.json b/MetaNodes/MetaNodes.en.json new file mode 100644 index 00000000..978e3608 --- /dev/null +++ b/MetaNodes/MetaNodes.en.json @@ -0,0 +1,24 @@ +{ + "Flow":{ + "Parts": { + "MovieLookup": { + "Description": "Looks performs a search on TheMovieDB.org.\nStores the Metadata inside the parameter 'MovieInfo'.\n\nOutputs 1: Movie found\nOutputs 2: Movie not found", + "Fields": { + "UseFolderName": "Use Folder Name", + "UseFolderName-Help": "If the folder name should be used instead of the filename." + } + }, + "MovieRenamer": { + "Description": "Renames the working file using the metadata stored in 'MovieInfo'.\nNote: MovieLookup should be executed in the flow before this node to work.\n\nOutput 1: File was renamed\nOutput 2: File failed to be renamed", + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "The pattern to use to rename the folder. '{Title}', '{Year}', '{Extension}'.", + "DestinationPath": "Destination Path", + "DestinationPath-Help": "If the file should be moved to a different directory.", + "LogOnly": "Log Only", + "LogOnly-Help": "Turn on if you just want to test this node without it actually renaming the file" + } + } + } + } +} \ No newline at end of file diff --git a/MetaNodes/Plugin.cs b/MetaNodes/Plugin.cs new file mode 100644 index 00000000..fae22c07 --- /dev/null +++ b/MetaNodes/Plugin.cs @@ -0,0 +1,11 @@ +namespace MetaNodes +{ + using System.ComponentModel.DataAnnotations; + + public class Plugin : FileFlows.Plugin.IPlugin + { + public string Name => "Meta Nodes"; + + public void Init() { } + } +} \ No newline at end of file diff --git a/MetaNodes/Tests/TestLogger.cs b/MetaNodes/Tests/TestLogger.cs new file mode 100644 index 00000000..c3dbeb02 --- /dev/null +++ b/MetaNodes/Tests/TestLogger.cs @@ -0,0 +1,43 @@ +namespace BasicNodes.Tests +{ + using FileFlows.Plugin; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + internal class TestLogger : ILogger + { + private List Messages = new List(); + + public void DLog(params object[] args) => Log("DBUG", args); + + public void ELog(params object[] args) => Log("ERRR", args); + + public void ILog(params object[] args) => Log("INFO", args); + + public void WLog(params object[] args) => Log("WARN", args); + + private void Log(string type, object[] args) + { + if (args == null || args.Length == 0) + return; + string message = type + " -> " + + string.Join(", ", args.Select(x => + x == null ? "null" : + x.GetType().IsPrimitive || x is string ? x.ToString() : + System.Text.Json.JsonSerializer.Serialize(x))); + Messages.Add(message); + } + + public bool Contains(string message) + { + if (string.IsNullOrWhiteSpace(message)) + return false; + + string log = string.Join(Environment.NewLine, Messages); + return log.Contains(message); + } + } +} diff --git a/MetaNodes/Tests/TheMovieDb/MovieLookupTests.cs b/MetaNodes/Tests/TheMovieDb/MovieLookupTests.cs new file mode 100644 index 00000000..20c8d81b --- /dev/null +++ b/MetaNodes/Tests/TheMovieDb/MovieLookupTests.cs @@ -0,0 +1,115 @@ +#if(DEBUG) + +namespace MetaNodes.Tests.TheMovieDb +{ + using BasicNodes.Tests; + using DM.MovieApi.MovieDb.Movies; + using MetaNodes.TheMovieDb; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MovieLookupTests + { + [TestMethod] + public void MovieLookupTests_File_Ghostbusters() + { + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters.mkv"); + args.Logger = new TestLogger(); + + MovieLookup ml = new MovieLookup(); + ml.UseFolderName = false; + + var result = ml.Execute(args); + Assert.AreEqual(1, result); + Assert.IsTrue(args.Parameters.ContainsKey(Globals.MOVIE_INFO)); + + var mi = args.Parameters[Globals.MOVIE_INFO] as MovieInfo; + Assert.IsNotNull(mi); + + Assert.AreEqual("Ghostbusters", mi.Title); + Assert.AreEqual(1984, mi.ReleaseDate.Year); + } + + [TestMethod] + public void MovieLookupTests_File_Ghostbusters2() + { + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters 2.mkv"); + args.Logger = new TestLogger(); + + MovieLookup ml = new MovieLookup(); + ml.UseFolderName = false; + + var result = ml.Execute(args); + Assert.AreEqual(1, result); + Assert.IsTrue(args.Parameters.ContainsKey(Globals.MOVIE_INFO)); + + var mi = args.Parameters[Globals.MOVIE_INFO] as MovieInfo; + Assert.IsNotNull(mi); + + Assert.AreEqual("Ghostbusters II", mi.Title); + Assert.AreEqual(1989, mi.ReleaseDate.Year); + } + + [TestMethod] + public void MovieLookupTests_File_WithDots() + { + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back.To.The.Future.2.mkv"); + args.Logger = new TestLogger(); + + MovieLookup ml = new MovieLookup(); + ml.UseFolderName = false; + + var result = ml.Execute(args); + Assert.AreEqual(1, result); + Assert.IsTrue(args.Parameters.ContainsKey(Globals.MOVIE_INFO)); + + var mi = args.Parameters[Globals.MOVIE_INFO] as MovieInfo; + Assert.IsNotNull(mi); + + Assert.AreEqual("Back to the Future Part II", mi.Title); + Assert.AreEqual(1989, mi.ReleaseDate.Year); + } + + [TestMethod] + public void MovieLookupTests_File_WithYear() + { + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back.To.The.Future.1989.mkv"); + args.Logger = new TestLogger(); + + MovieLookup ml = new MovieLookup(); + ml.UseFolderName = false; + + var result = ml.Execute(args); + Assert.AreEqual(1, result); + Assert.IsTrue(args.Parameters.ContainsKey(Globals.MOVIE_INFO)); + + var mi = args.Parameters[Globals.MOVIE_INFO] as MovieInfo; + Assert.IsNotNull(mi); + + Assert.AreEqual("Back to the Future Part II", mi.Title); + Assert.AreEqual(1989, mi.ReleaseDate.Year); + } + + [TestMethod] + public void MovieLookupTests_Folder_WithYear() + { + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Back To The Future (1989)\Jaws.mkv"); + args.Logger = new TestLogger(); + + MovieLookup ml = new MovieLookup(); + ml.UseFolderName = true; + + var result = ml.Execute(args); + Assert.AreEqual(1, result); + Assert.IsTrue(args.Parameters.ContainsKey(Globals.MOVIE_INFO)); + + var mi = args.Parameters[Globals.MOVIE_INFO] as MovieInfo; + Assert.IsNotNull(mi); + + Assert.AreEqual("Back to the Future Part II", mi.Title); + Assert.AreEqual(1989, mi.ReleaseDate.Year); + } + } +} + +#endif \ No newline at end of file diff --git a/MetaNodes/Tests/TheMovieDb/MovieRenamerTests.cs b/MetaNodes/Tests/TheMovieDb/MovieRenamerTests.cs new file mode 100644 index 00000000..cf7b3433 --- /dev/null +++ b/MetaNodes/Tests/TheMovieDb/MovieRenamerTests.cs @@ -0,0 +1,134 @@ +#if(DEBUG) + +namespace MetaNodes.Tests.TheMovieDb +{ + using BasicNodes.Tests; + using DM.MovieApi.MovieDb.Movies; + using MetaNodes.TheMovieDb; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class RenamerTests + { + [TestMethod] + public void RenamerTests_File_TitleYearExt() + { + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters.mkv"); + var logger = new TestLogger(); + args.Logger = logger; + args.SetParameter(Globals.MOVIE_INFO, new MovieInfo + { + Title = "Back to the Future Part II", + ReleaseDate = new DateTime(1989, 5, 5) + }); + + Renamer node = new Renamer(); + node.Pattern = "{Title} ({Year}).{ext}"; + node.LogOnly = true; + + var result = node.Execute(args); + Assert.AreEqual(1, result); + + Assert.IsTrue(logger.Contains("Renaming file to: Back to the Future Part II (1989).mkv")); + } + + [TestMethod] + public void RenamerTests_File_TitleExt() + { + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters.mkv"); + var logger = new TestLogger(); + args.Logger = logger; + args.SetParameter(Globals.MOVIE_INFO, new MovieInfo + { + Title = "Back to the Future Part II", + ReleaseDate = new DateTime(1989, 5, 5) + }); + + Renamer node = new Renamer(); + node.Pattern = "{Title}.{ext}"; + node.LogOnly = true; + + var result = node.Execute(args); + Assert.AreEqual(1, result); + + Assert.IsTrue(logger.Contains("Renaming file to: Back to the Future Part II.mkv")); + } + + [TestMethod] + public void RenamerTests_Folder_TitleYear_Windows() + { + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters.mkv"); + var logger = new TestLogger(); + args.Logger = logger; + args.SetParameter(Globals.MOVIE_INFO, new MovieInfo + { + Title = "Back to the Future Part II", + ReleaseDate = new DateTime(1989, 5, 5) + }); + + Renamer node = new Renamer(); + node.Pattern = @"{Title} ({Year})\{Title}.{ext}"; + node.LogOnly = true; + + var result = node.Execute(args); + Assert.AreEqual(1, result); + + Assert.IsTrue(logger.Contains($"Renaming file to: Back to the Future Part II (1989){Path.DirectorySeparatorChar}Back to the Future Part II.mkv")); + } + + [TestMethod] + public void RenamerTests_Folder_TitleYear_Linux() + { + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\Ghostbusters.mkv"); + var logger = new TestLogger(); + args.Logger = logger; + args.SetParameter(Globals.MOVIE_INFO, new MovieInfo + { + Title = "Back to the Future Part II", + ReleaseDate = new DateTime(1989, 5, 5) + }); + + Renamer node = new Renamer(); + node.Pattern = @"{Title} ({Year})/{Title}.{ext}"; + node.LogOnly = true; + + var result = node.Execute(args); + Assert.AreEqual(1, result); + + Assert.IsTrue(logger.Contains($"Renaming file to: Back to the Future Part II (1989){Path.DirectorySeparatorChar}Back to the Future Part II.mkv")); + } + + [TestMethod] + public void RenamerTests_Folder_TitleYear_MoveActual() + { + string tempFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".mkv"); + string path = new FileInfo(tempFile).DirectoryName; + File.WriteAllText(tempFile, "test"); + + var args = new FileFlows.Plugin.NodeParameters(tempFile); + var logger = new TestLogger(); + args.Logger = logger; + args.SetParameter(Globals.MOVIE_INFO, new MovieInfo + { + Title = "Back to the Future Part II", + ReleaseDate = new DateTime(1989, 5, 5) + }); + + Renamer node = new Renamer(); + node.Pattern = @"{Title} ({Year})/{Title}.{ext}"; + + var result = node.Execute(args); + Assert.AreEqual(1, result); + + string expectedShort = $"Back to the Future Part II (1989){Path.DirectorySeparatorChar}Back to the Future Part II.mkv"; + Assert.IsTrue(logger.Contains($"Renaming file to: " + expectedShort)); + + string expected = Path.Combine(path, expectedShort); + Assert.IsTrue(File.Exists(expected)); + + Directory.Delete(new FileInfo(expected).DirectoryName, true); + } + } +} + +#endif \ No newline at end of file diff --git a/MetaNodes/TheMovieDb/MovieLookup.cs b/MetaNodes/TheMovieDb/MovieLookup.cs new file mode 100644 index 00000000..8647733c --- /dev/null +++ b/MetaNodes/TheMovieDb/MovieLookup.cs @@ -0,0 +1,105 @@ +namespace MetaNodes.TheMovieDb +{ + using System.Text.RegularExpressions; + using DM.MovieApi; + using DM.MovieApi.ApiResponse; + using DM.MovieApi.MovieDb.Movies; + using FileFlows.Plugin; + using FileFlows.Plugin.Attributes; + + public class MovieLookup : Node + { + public override int Inputs => 1; + public override int Outputs => 2; + public override string Icon => "fas fa-film"; + + + [Boolean(1)] + public bool UseFolderName { get; set; } + + public override int Execute(NodeParameters args) + { + var fileInfo = new FileInfo(args.FileName); + string lookupName = UseFolderName ? fileInfo.Directory.Name : fileInfo.Name.Substring(0, fileInfo.Name.LastIndexOf(fileInfo.Extension)); + lookupName = lookupName.Replace(".", " ").Replace("_", " "); + + // look for year + string year = string.Empty; + var match = Regex.Match(lookupName, @"((19[2-9][0-9])|(20[0-9]{2}))(?=([\.\s_\-\)\]]|$))"); + if (match.Success) + { + year = match.Groups[1].Value; + lookupName = lookupName.Replace(year, ""); + } + + // remove double spaces incase they were added when removing the year + while (lookupName.IndexOf(" ") > 0) + lookupName = lookupName.Replace(" ", " "); + + string bearerToken = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxZjVlNTAyNmJkMDM4YmZjZmU2MjI2MWU2ZGEwNjM0ZiIsInN1YiI6IjRiYzg4OTJjMDE3YTNjMGY5MjAwMDIyZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.yMwyT8DEK1rF1gQMKJ-ZSy-dUGxFs5T345XwBLrvrWE"; + + // RegisterSettings only needs to be called one time when your application starts-up. + MovieDbFactory.RegisterSettings(bearerToken); + + var movieApi = MovieDbFactory.Create().Value; + + + ApiSearchResponse response = movieApi.SearchByTitleAsync(lookupName).Result; + + // try find an exact match + var result = response.Results.OrderBy(x => + { + if (string.IsNullOrEmpty(year) == false) + { + return year == x.ReleaseDate.Year.ToString() ? 0 : 1; + } + return 0; + }) + .ThenBy(x => x.Title.ToLower().Trim().Replace(" ", "") == lookupName.ToLower().Trim().Replace(" ", "") ? 0 : 1) + .ThenBy(x => + { + // do some fuzzy logic with roman numerals + var numMatch = Regex.Match(lookupName, @"[\s]([\d]+)$"); + if (numMatch.Success == false) + return 0; + int number = int.Parse(numMatch.Groups[1].Value); + string roman = number switch + { + 1 => "i", + 2 => "ii", + 3 => "iii", + 4 => "iv", + 5 => "v", + 6 => "vi,", + 7 => "vii", + 8 => "viii", + 9 => "ix", + 10 => "x", + 11 => "xi", + 12 => "xii", + 13 => "xiii", + _ => string.Empty + }; + string ln = lookupName.Substring(0, lookupName.LastIndexOf(number.ToString())).ToLower().Trim().Replace(" ", ""); + string softTitle = x.Title.ToLower().Replace(" ", "").Trim(); + if (softTitle == ln + roman) + return 0; + if (softTitle.StartsWith(ln) && softTitle.EndsWith(roman)) + return 0; + return 1; + }) + .ThenBy(x => lookupName.ToLower().Trim().Replace(" ", "").StartsWith(x.Title.ToLower().Trim().Replace(" ", "")) ? 0 : 1) + .ThenBy(x => x.Title) + .FirstOrDefault(); + + if (result == null) + return 2; // no match + + args.SetParameter(Globals.MOVIE_INFO, result); + + return 1; + + } + + } +} \ No newline at end of file diff --git a/MetaNodes/TheMovieDb/MovieRenamer.cs b/MetaNodes/TheMovieDb/MovieRenamer.cs new file mode 100644 index 00000000..2efbbed8 --- /dev/null +++ b/MetaNodes/TheMovieDb/MovieRenamer.cs @@ -0,0 +1,80 @@ +namespace MetaNodes.TheMovieDb +{ + using System.Text.RegularExpressions; + using DM.MovieApi; + using DM.MovieApi.ApiResponse; + using DM.MovieApi.MovieDb.Movies; + using FileFlows.Plugin; + using FileFlows.Plugin.Attributes; + + public class MovieRenamer : Node + { + public override int Inputs => 1; + public override int Outputs => 1; + public override string Icon => "fas fa-font"; + + public string _Pattern = string.Empty; + + [Text(1)] + public string? Pattern + { + get => _Pattern; + set { _Pattern = value ?? ""; } + } + + private string _DestinationPath = string.Empty; + + [Folder(2)] + public string DestinationPath + { + get => _DestinationPath; + set { _DestinationPath = value ?? ""; } + } + + [Boolean(3)] + public bool LogOnly { get; set; } + + public override int Execute(NodeParameters args) + { + if(string.IsNullOrEmpty(Pattern)) + { + args.Logger?.ELog("No pattern specified"); + return -1; + } + var movieInfo = args.GetParameter(Globals.MOVIE_INFO); + if (movieInfo == null) { + args.Logger?.ELog("MovieInfo not found, you must execute the Movie Lookup node first"); + return -1; + } + + string newFile = Pattern; + // incase they set a linux path on windows or vice versa + newFile = newFile.Replace('\\', Path.DirectorySeparatorChar); + newFile = newFile.Replace('/', Path.DirectorySeparatorChar); + + newFile = ReplaceVariable(newFile, "Year", movieInfo.ReleaseDate.Year.ToString()); + newFile = ReplaceVariable(newFile, "Title", movieInfo.Title); + newFile = ReplaceVariable(newFile, "Extension", args.WorkingFile.Substring(args.WorkingFile.LastIndexOf(".")+1)); + newFile = ReplaceVariable(newFile, "Ext", args.WorkingFile.Substring(args.WorkingFile.LastIndexOf(".") + 1)); + + string destFolder = DestinationPath; + if (string.IsNullOrEmpty(destFolder)) + destFolder = new FileInfo(args.WorkingFile).Directory?.FullName ?? ""; + + var dest = new FileInfo(Path.Combine(destFolder, newFile)); + + args.Logger?.ILog("Renaming file to: " + (string.IsNullOrEmpty(DestinationPath) ? "" : DestinationPath + Path.DirectorySeparatorChar) + newFile); + + + if (LogOnly) + return 1; + + return args.MoveFile(dest.FullName) ? 1 : -1; + } + + private string ReplaceVariable(string input, string variable, string value) + { + return Regex.Replace(input, @"{" + Regex.Escape(variable) + @"}", value, RegexOptions.IgnoreCase); + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/ApiRequestBase.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/ApiRequestBase.cs new file mode 100644 index 00000000..b414d768 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/ApiRequestBase.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using DM.MovieApi.ApiResponse; +using Newtonsoft.Json; + +namespace DM.MovieApi.ApiRequest +{ + internal abstract class ApiRequestBase + { + private readonly IApiSettings _settings; + + protected ApiRequestBase( IApiSettings settings ) + { + _settings = settings; + } + + public async Task> QueryAsync( string command ) + => await QueryAsync( command, new Dictionary() ); + + public async Task> QueryAsync( string command, IDictionary parameters ) + { + var settings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + DateFormatHandling = DateFormatHandling.IsoDateFormat, + }; + settings.Converters.Add( new IsoDateTimeConverterEx() ); + + Func deserializer = json => JsonConvert.DeserializeObject( json, settings ); + + return await QueryAsync( command, parameters, deserializer ); + } + + public async Task> QueryAsync( string command, Func deserializer ) + => await QueryAsync( command, new Dictionary(), deserializer ); + + public async Task> QueryAsync( string command, IDictionary parameters, Func deserializer ) + { + using( HttpClient client = CreateClient() ) + { + string cmd = CreateCommand( command, parameters ); + + HttpResponseMessage response = await client.GetAsync( cmd ).ConfigureAwait( false ); + + string json = await response.Content.ReadAsStringAsync().ConfigureAwait( false ); + + if( !response.IsSuccessStatusCode ) + { + // rate limit will not exist if there is an error. + var error = new ApiQueryResponse + { + Error = JsonConvert.DeserializeObject( json ), + CommandText = response.RequestMessage.RequestUri.ToString(), + Json = json, + }; + + return error; + } + + var result = new ApiQueryResponse + { + CommandText = response.RequestMessage.RequestUri.ToString(), + Json = json, + }; + + T item = deserializer( json ); + result.Item = item; + return result; + } + } + + public async Task> SearchAsync( string command ) + => await SearchAsync( command, 1 ); + + public async Task> SearchAsync( string command, int pageNumber ) + => await SearchAsync( command, pageNumber, new Dictionary() ); + + public async Task> SearchAsync( string command, IDictionary parameters ) + => await SearchAsync( command, 1, parameters ); + + public async Task> SearchAsync( string command, int pageNumber, IDictionary parameters ) + { + pageNumber = pageNumber < 1 ? 1 : pageNumber; + pageNumber = pageNumber > 1000 ? 1000 : pageNumber; + + if( !parameters.Keys.Contains( "page", StringComparer.OrdinalIgnoreCase ) ) + { + parameters.Add( "page", pageNumber.ToString() ); + } + + using( HttpClient client = CreateClient() ) + { + string cmd = CreateCommand( command, parameters ); + + HttpResponseMessage response = await client.GetAsync( cmd ).ConfigureAwait( false ); + + string json = await response.Content.ReadAsStringAsync().ConfigureAwait( false ); + + // rate limit will not exist if there is an error. + if( !response.IsSuccessStatusCode ) + { + var error = new ApiSearchResponse + { + // This will throw up if the error is page number = 0; the resultant json will be: {"errors":["page must be greater than 0"]} + // in other words, the json will not include a status_code. Asked the api devs and this is a known issue they are working on. + // What to do? Nothing really, the page guard at the top of the method will keep the page number > 0. + Error = JsonConvert.DeserializeObject( json ), + CommandText = response.RequestMessage.RequestUri.ToString(), + Json = json, + }; + + return error; + } + + var result = JsonConvert.DeserializeObject>( json, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore } ); + + result.CommandText = response.RequestMessage.RequestUri.ToString(); + result.Json = json; + + return result; + } + } + + protected HttpClient CreateClient() + { + var handler = new HttpClientHandler + { + AllowAutoRedirect = false, + UseCookies = false, + UseDefaultCredentials = true, + AutomaticDecompression = DecompressionMethods.GZip, + }; + + var client = new HttpClient( handler ); + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue( "application/json" ) ); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Bearer", _settings.BearerToken ); + client.BaseAddress = new Uri( _settings.ApiUrl ); + + return client; + } + + protected string CreateCommand( string rootCommand ) + => CreateCommand( rootCommand, new Dictionary() ); + + protected string CreateCommand( string rootCommand, IDictionary parameters ) + { + string tokens = parameters.Any() + ? string.Join( "&", parameters.Select( x => x.Key + "=" + x.Value ) ) + : string.Empty; + + if( string.IsNullOrWhiteSpace( tokens ) == false ) + { + rootCommand += $"?{tokens}"; + } + + return rootCommand; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/IApiRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/IApiRequest.cs new file mode 100644 index 00000000..809449c6 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/IApiRequest.cs @@ -0,0 +1,8 @@ +namespace DM.MovieApi.ApiRequest +{ + /// + /// Interface to provide a constraint for all MovieDb Api Request interfaces/classes. + /// + public interface IApiRequest + { } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/IsoDateTimeConverterEx.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/IsoDateTimeConverterEx.cs new file mode 100644 index 00000000..a56ea147 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiRequest/IsoDateTimeConverterEx.cs @@ -0,0 +1,56 @@ +using System; +using System.Diagnostics; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace DM.MovieApi.ApiRequest +{ + /// + /// Extends the native Newtonsoft IsoDateTimeConverter to allow deserializing partial dates. + /// + public class IsoDateTimeConverterEx : IsoDateTimeConverter + { + /// + /// Reads the JSON representation of the object. + /// + /// The Newtonsoft.Json.JsonReader to read from. + /// Type of the object. + /// The existing value of object being read. + /// The calling serializer. + /// The object value. + public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) + { + ConditionalTraceReaderValue( reader ); + + try + { + return base.ReadJson( reader, objectType, existingValue, serializer ); + } + catch( Exception ex ) when( ex is FormatException + || ex is JsonSerializationException jse + && jse.Message.Contains( "System.DateTime" ) ) + { + string val = reader.Value?.ToString(); + + if( val?.Length == 4 && int.TryParse( val, out int year ) ) + { + return new DateTime( year, 1, 1 ); + } + + return default( DateTime ); + } + } + + [Conditional( "DEBUG" )] + private void ConditionalTraceReaderValue( JsonReader reader ) + { + string val = reader.Value?.ToString(); + if( string.IsNullOrWhiteSpace( val ) ) + { + val = ""; + } + + Debug.WriteLine( $"IsoDateTimeConverterEx.JsonReader.Value: {val}" ); + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiError.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiError.cs new file mode 100644 index 00000000..696d79fe --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiError.cs @@ -0,0 +1,33 @@ +using System; +using System.Runtime.Serialization; + +namespace DM.MovieApi.ApiResponse +{ + [DataContract] + public class ApiError + { + private int _statusCode; + + [DataMember( Name = "status_code" )] + public int StatusCode + { + get => _statusCode; + private set + { + _statusCode = value; + + TmdbStatusCode = Enum.IsDefined( typeof( TmdbStatusCode ), _statusCode ) + ? ( TmdbStatusCode )_statusCode + : TmdbStatusCode.Unknown; + } + } + + [DataMember( Name = "status_message" )] + public string Message { get; private set; } + + public TmdbStatusCode TmdbStatusCode { get; private set; } + + public override string ToString() + => $"Status: {StatusCode}: {Message}"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiQueryResponse.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiQueryResponse.cs new file mode 100644 index 00000000..0551d511 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiQueryResponse.cs @@ -0,0 +1,17 @@ +namespace DM.MovieApi.ApiResponse +{ + /// + /// Standard response from an API call returning a single specific result. + /// Multiple item based based results (i.e., searches) are returned with an . + /// + public class ApiQueryResponse : ApiResponseBase + { + /// + /// The item returned from the API call. + /// + public T Item { get; internal set; } + + public override string ToString() + => Item.ToString(); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiResponseBase.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiResponseBase.cs new file mode 100644 index 00000000..e151fd2a --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiResponseBase.cs @@ -0,0 +1,26 @@ +namespace DM.MovieApi.ApiResponse +{ + /// + /// Base class for all API responses from themoviedb.org. + /// + public abstract class ApiResponseBase + { + /// + /// Contains specific error information if an error was encountered during the API call to themoviedb.org. + /// + public ApiError Error { get; internal set; } + + /// + /// The API command text used for the API call to themoviedb.org. + /// + public string CommandText { get; internal set; } + + /// + /// The JSON returned from themoviedb.org based on the query. + /// + public string Json { get; internal set; } + + public override string ToString() + => CommandText; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiSearchResponse.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiSearchResponse.cs new file mode 100644 index 00000000..80efba23 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/ApiSearchResponse.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +// ReSharper disable UnusedAutoPropertyAccessor.Local + +namespace DM.MovieApi.ApiResponse +{ + /// + /// Standard response from an API call returning a more than one result, i.e., a Search Result. + /// Single item based results are returned with an + /// . + /// + [DataContract] + public class ApiSearchResponse : ApiResponseBase + { + /// + /// The list of results from the search. + /// + [DataMember( Name = "results" )] + public IReadOnlyList Results { get; private set; } + + /// + /// The current page number of the search result. + /// + [DataMember( Name = "page" )] + public int PageNumber { get; private set; } + + /// + /// The total number of pages found from the search result. + /// + [DataMember( Name = "total_pages" )] + public int TotalPages { get; private set; } + + /// + /// The total number of results from the search. + /// + [DataMember( Name = "total_results" )] + public int TotalResults { get; private set; } + + public override string ToString() + => $"Page {PageNumber} of {TotalPages} ({TotalResults} total results)"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/TmdbStatusCode.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/TmdbStatusCode.cs new file mode 100644 index 00000000..235d9049 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/ApiResponse/TmdbStatusCode.cs @@ -0,0 +1,217 @@ +using System.Diagnostics.CodeAnalysis; + +namespace DM.MovieApi.ApiResponse +{ + /// + /// themoviedb.org Status Codes as defined by: https://www.themoviedb.org/documentation/api/status-codes + /// + [SuppressMessage( "ReSharper", "UnusedMember.Global" )] + public enum TmdbStatusCode + { + Unknown = 0, + + /// + /// 200: Success. + /// + //[Description( "200: Success." )] + Success = 1, + + /// + /// 501: Invalid service: this service does not exist. + /// + //[Description( "501: Invalid service: this service does not exist." )] + InvalidService = 2, + + /// + /// 401: Authentication failed: You do not have permissions to access the service. + /// + //[Description( "401: Authentication failed: You do not have permissions to access the service." )] + InsufficientPermissions = 3, + + /// + /// 405: Invalid format: This service doesn't exist in that format. + /// + //[Description( "405: Invalid format: This service doesn't exist in that format." )] + InvalidFormat = 4, + + /// + /// 422: Invalid parameters: Your request parameters are incorrect. + /// + //[Description( "422: Invalid parameters: Your request parameters are incorrect." )] + InvalidParameters = 5, + + /// + /// 404: Invalid id: The pre-requisite id is invalid or not found. + /// + //[Description( "404: Invalid id: The pre-requisite id is invalid or not found." )] + InvalidId = 6, + + /// + /// 401: Invalid API key: You must be granted a valid key. + /// + //[Description( "401: Invalid API key: You must be granted a valid key." )] + InvalidApiKey = 7, + + /// + /// 403: Duplicate entry: The data you tried to submit already exists. + /// + //[Description( "403: Duplicate entry: The data you tried to submit already exists." )] + DuplicateEntry = 8, + + /// + /// 503: Service offline: This service is temporarily offline, try again later. + /// + //[Description( "503: Service offline: This service is temporarily offline, try again later." )] + ServiceOffline = 9, + + /// + /// 503: Service offline: This service is temporarily offline, try again later. + /// + //[Description( "401: Suspended API key: Access to your account has been suspended, contact TMDb." )] + SuspendedApiKey = 10, + + /// + /// 503: Service offline: This service is temporarily offline, try again later. + /// + //[Description( "500: Internal error: Something went wrong, contact TMDb." )] + InternalError = 11, + + /// + /// 201: The item/record was updated successfully. + /// + //[Description( "201: The item/record was updated successfully." )] + SuccessfulUpdate = 12, + + /// + /// 200: The item/record was deleted successfully. + /// + //[Description( "200: The item/record was deleted successfully." )] + SuccessfulDelete = 13, + + /// + /// 401: Authentication failed. + /// + //[Description( "401: Authentication failed." )] + AuthenticationFailed = 14, + + /// + /// 500: Failed. + /// + //[Description( "500: Failed." )] + Failed = 15, + + /// + /// 401: Device denied. + /// + //[Description( "401: Device denied." )] + DeviceDenied = 16, + + /// + /// 401: Session denied. + /// + //[Description( "401: Session denied." )] + SessionDenied = 17, + + /// + /// 400: Validation failed. + /// + //[Description( "400: Validation failed." )] + ValidationFailed = 18, + + /// + /// 406: Invalid accept header. + /// + //[Description( "406: Invalid accept header." )] + InvalidAcceptHeader = 19, + + /// + /// 422: Invalid date range: Should be a range no longer than 14 days. + /// + //[Description( "422: Invalid date range: Should be a range no longer than 14 days." )] + InvalidDateRange = 20, + + /// + /// 200: Entry not found: The item you are trying to edit cannot be found. + /// + //[Description( "200: Entry not found: The item you are trying to edit cannot be found." )] + EntryNotFound = 21, + + /// + /// 400: Invalid page: Pages start at 1 and max at 1000. They are expected to be an integer. + /// + //[Description( "400: Invalid page: Pages start at 1 and max at 1000. They are expected to be an integer." )] + InvalidPage = 22, + + /// + /// 400: Invalid date: Format needs to be YYYY-MM-DD. + /// + //[Description( "400: Invalid date: Format needs to be YYYY-MM-DD." )] + InvalidDate = 23, + + /// + /// 400: Invalid date: Format needs to be YYYY-MM-DD. + /// + //[Description( "504: Your request to the backend server timed out. Try again." )] + ServerTimeout = 24, + + /// + /// 400: Invalid date: Format needs to be YYYY-MM-DD. + /// + //[Description( "429: Your request count (#) is over the allowed limit of (40)." )] + RequestOverLimit = 25, + + /// + /// "400: You must provide a username and password. + /// + //[Description( "400: You must provide a username and password." )] + AuthenticationRequired = 26, + + /// + /// 400: Too many append to response objects: The maximum number of remote calls is 20. + /// + //[Description( "400: Too many append to response objects: The maximum number of remote calls is 20." )] + ResponseObjectOverflow = 27, + + /// + /// 400: Invalid timezone: Please consult the documentation for a valid timezone. + /// + //[Description( "400: Invalid timezone: Please consult the documentation for a valid timezone." )] + InvalidTimezone = 28, + + /// + /// 400: Invalid timezone: Please consult the documentation for a valid timezone. + /// + //[Description( "400: You must confirm this action: Please provide a confirm=true parameter." )] + ActionMustBeConfirmed = 29, + + /// + /// 401: Invalid username and/or password: You did not provide a valid login. + /// + //[Description( "401: Invalid username and/or password: You did not provide a valid login." )] + InvalidAuthentication = 30, + + /// + /// 401: Account disabled: Your account is no longer active. Contact TMDb if this is an error. + /// + //[Description( "401: Account disabled: Your account is no longer active. Contact TMDb if this is an error." )] + AccountDisabled = 31, + + /// + /// 401: Email not verified: Your email address has not been verified. + /// + //[Description( "401: Email not verified: Your email address has not been verified." )] + EmailNotVerified = 32, + + /// + /// 401: Invalid request token: The request token is either expired or invalid. + /// + //[Description( "401: Invalid request token: The request token is either expired or invalid." )] + InvalidRequestToken = 33, + + /// + /// 401: The resource you requested could not be found. + /// + //[Description( "401: The resource you requested could not be found." )] + ResourceNotFound = 34, + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/IApiSettings.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/IApiSettings.cs new file mode 100644 index 00000000..d90d93bd --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/IApiSettings.cs @@ -0,0 +1,9 @@ +namespace DM.MovieApi +{ + internal interface IApiSettings + { + string ApiUrl { get; } + + string BearerToken { get; } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/IMovieDbApi.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/IMovieDbApi.cs new file mode 100644 index 00000000..bf525b45 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/IMovieDbApi.cs @@ -0,0 +1,58 @@ +using DM.MovieApi.MovieDb.Certifications; +using DM.MovieApi.MovieDb.Companies; +using DM.MovieApi.MovieDb.Configuration; +using DM.MovieApi.MovieDb.Genres; +using DM.MovieApi.MovieDb.IndustryProfessions; +using DM.MovieApi.MovieDb.Movies; +using DM.MovieApi.MovieDb.People; +using DM.MovieApi.MovieDb.TV; + +namespace DM.MovieApi +{ + /// + /// Global interface exposing all API interfaces against themoviedb.org that are + /// currently available in this release. + /// + public interface IMovieDbApi + { + /// + /// Provides access for retrieving production company information. + /// + IApiCompanyRequest Companies { get; } + + /// + /// Provides access for retrieving themoviedb.org configuration information. + /// + IApiConfigurationRequest Configuration { get; } + + /// + /// Provides access for retrieving Movie and TV genres. + /// + IApiGenreRequest Genres { get; } + + /// + /// Provides access for retrieving information about Movie/TV industry specific professions. + /// + IApiProfessionRequest IndustryProfessions { get; } + + /// + /// Provides access for retrieving information about Movies. + /// + IApiMovieRequest Movies { get; } + + /// + /// Provides access for retrieving movie rating information. + /// + IApiMovieRatingRequest MovieRatings { get; } + + /// + /// Provides access for retrieving information about Television shows. + /// + IApiTVShowRequest Television { get; } + + /// + /// Provides access for retrieving information about People. + /// + IApiPeopleRequest People { get; } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/LICENSE b/MetaNodes/ThirdParty/TheMovieDbWrapper/LICENSE new file mode 100644 index 00000000..d2bb5f40 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 kindler chase + +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. diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/ApiMovieRatingRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/ApiMovieRatingRequest.cs new file mode 100644 index 00000000..922cb3e6 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/ApiMovieRatingRequest.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.Shims; +using Newtonsoft.Json.Linq; + +namespace DM.MovieApi.MovieDb.Certifications +{ + internal class ApiMovieRatingRequest : ApiRequestBase, IApiMovieRatingRequest + { + [ImportingConstructor] + public ApiMovieRatingRequest( IApiSettings settings ) + : base( settings ) + { } + + public async Task> GetMovieRatingsAsync() + { + const string command = "certification/movie/list"; + + ApiQueryResponse response = await base.QueryAsync( command, RatingsDeserializer ); + + return response; + } + + private MovieRatings RatingsDeserializer( string json ) + { + var obj = JObject.Parse( json ); + + JToken certs = obj["certifications"]; + + // ReSharper disable once PossibleNullReferenceException + var ratings = certs.ToObject(); + + Func, IReadOnlyList> reorder = + list => list.OrderBy( x => x.Order ).ThenBy( x => x.Rating ).ToList().AsReadOnly(); + + // ReSharper disable once PossibleNullReferenceException + ratings.Australia = reorder( ratings.Australia ); + ratings.Canada = reorder( ratings.Canada ); + ratings.France = reorder( ratings.France ); + ratings.Germany = reorder( ratings.Germany ); + ratings.India = reorder( ratings.India ); + ratings.NewZealand = reorder( ratings.NewZealand ); + ratings.UnitedKingdom = reorder( ratings.UnitedKingdom ); + ratings.UnitedStates = reorder( ratings.UnitedStates ); + + return ratings; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/IApiMovieRatingRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/IApiMovieRatingRequest.cs new file mode 100644 index 00000000..337a7490 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/IApiMovieRatingRequest.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; + +namespace DM.MovieApi.MovieDb.Certifications +{ + /// + /// Interface for retrieving movie rating information. + /// + public interface IApiMovieRatingRequest : IApiRequest + { + /// + /// Gets the list of supported certifications (movie ratings) for movies. + /// + Task> GetMovieRatingsAsync(); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/MovieRatings.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/MovieRatings.cs new file mode 100644 index 00000000..afd99e16 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Certifications/MovieRatings.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Certifications +{ + [DataContract] + public class Certification + { + [DataMember( Name = "certification" )] + public string Rating { get; set; } + + [DataMember( Name = "meaning" )] + public string Meaning { get; set; } + + [DataMember( Name = "order" )] + public int Order { get; set; } + + public override string ToString() + => $"{Rating}: {Meaning.Substring( 75 )}"; + } + + [DataContract] + public class MovieRatings + { + [DataMember( Name = "AU" )] + public IReadOnlyList Australia { get; set; } + + [DataMember( Name = "CA" )] + public IReadOnlyList Canada { get; set; } + + [DataMember( Name = "FR" )] + public IReadOnlyList France { get; set; } + + [DataMember( Name = "DE" )] + public IReadOnlyList Germany { get; set; } + + [DataMember( Name = "IN" )] + public IReadOnlyList India { get; set; } + + [DataMember( Name = "NZ" )] + public IReadOnlyList NewZealand { get; set; } + + [DataMember( Name = "US" )] + public IReadOnlyList UnitedStates { get; set; } + + [DataMember( Name = "GB" )] + public IReadOnlyList UnitedKingdom { get; set; } + + public MovieRatings() + { + UnitedStates = Array.Empty(); + Canada = Array.Empty(); + Australia = Array.Empty(); + Germany = Array.Empty(); + France = Array.Empty(); + NewZealand = Array.Empty(); + India = Array.Empty(); + UnitedKingdom = Array.Empty(); + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Collections/CollectionInfo.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Collections/CollectionInfo.cs new file mode 100644 index 00000000..e1e7d2c9 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Collections/CollectionInfo.cs @@ -0,0 +1,30 @@ +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Collections +{ + [DataContract] + public class CollectionInfo + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + + [DataMember( Name = "backdrop_path" )] + public string BackdropPath { get; set; } + + public override string ToString() + { + if( string.IsNullOrWhiteSpace( Name ) ) + { + return "n/a"; + } + + return $"{Name} ({Id})"; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ApiCompanyRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ApiCompanyRequest.cs new file mode 100644 index 00000000..bdc7dc4f --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ApiCompanyRequest.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.MovieDb.Genres; +using DM.MovieApi.MovieDb.Movies; +using DM.MovieApi.Shims; + +namespace DM.MovieApi.MovieDb.Companies +{ + internal class ApiCompanyRequest : ApiRequestBase, IApiCompanyRequest + { + private readonly IApiGenreRequest _genreApi; + + [ImportingConstructor] + public ApiCompanyRequest( IApiSettings settings, IApiGenreRequest genreApi ) + : base( settings ) + { + _genreApi = genreApi; + } + + public async Task> FindByIdAsync( int companyId ) + { + string command = $"company/{companyId}"; + + ApiQueryResponse response = await base.QueryAsync( command ); + + return response; + } + + public async Task> GetMoviesAsync( int companyId, int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + }; + + string command = $"company/{companyId}/movies"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + if( response.Error != null ) + { + return response; + } + + response.Results.PopulateGenres( _genreApi ); + + return response; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/IApiCompanyRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/IApiCompanyRequest.cs new file mode 100644 index 00000000..5a7cbef5 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/IApiCompanyRequest.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.MovieDb.Movies; + +namespace DM.MovieApi.MovieDb.Companies +{ + /// + /// Interface for retrieving information about a production company. + /// + public interface IApiCompanyRequest : IApiRequest + { + /// + /// Gets all the basic information about a specific company. + /// + /// The company Id is typically found from a Movie or TV query. + Task> FindByIdAsync( int companyId ); + + /// + /// Get the list of movies associated with a particular company. + /// + /// The company Id is typically found from a Movie or TV query. + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + /// + Task> GetMoviesAsync( int companyId, int pageNumber = 1, string language = "en" ); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ParentCompany.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ParentCompany.cs new file mode 100644 index 00000000..4600a586 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ParentCompany.cs @@ -0,0 +1,27 @@ +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Companies +{ + [DataContract] + public class ParentCompany + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "logo_path" )] + public string LogoPath { get; set; } + + public override string ToString() + { + if( string.IsNullOrWhiteSpace( Name ) ) + { + return "n/a"; + } + + return $"{Name} ({Id})"; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ProductionCompany.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ProductionCompany.cs new file mode 100644 index 00000000..2daa3c10 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ProductionCompany.cs @@ -0,0 +1,32 @@ +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Companies +{ + [DataContract] + public class ProductionCompany + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "description" )] + public string Description { get; set; } + + [DataMember( Name = "headquarters" )] + public string Headquarters { get; set; } + + [DataMember( Name = "homepage" )] + public string Homepage { get; set; } + + [DataMember( Name = "logo_path" )] + public string LogoPath { get; set; } + + [DataMember( Name = "parent_company" )] + public ParentCompany ParentCompany { get; set; } + + public override string ToString() + => $"{Name} ({Id})"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ProductionCompanyInfo.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ProductionCompanyInfo.cs new file mode 100644 index 00000000..54266b31 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Companies/ProductionCompanyInfo.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Companies +{ + [DataContract] + public class ProductionCompanyInfo : IEqualityComparer + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + public ProductionCompanyInfo( int id, string name ) + { + Id = id; + Name = name; + } + + public override bool Equals( object obj ) + { + if( obj is not ProductionCompanyInfo info ) + { + return false; + } + + return Equals( this, info ); + } + + public bool Equals( ProductionCompanyInfo x, ProductionCompanyInfo y ) + => x != null && y != null && x.Id == y.Id && x.Name == y.Name; + + public override int GetHashCode() + => GetHashCode( this ); + + public int GetHashCode( ProductionCompanyInfo obj ) + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + obj.Id.GetHashCode(); + hash = hash * 23 + obj.Name.GetHashCode(); + return hash; + } + } + + public override string ToString() + { + if( string.IsNullOrWhiteSpace( Name ) ) + { + return "n/a"; + } + + return $"{Name} ({Id})"; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ApiConfiguration.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ApiConfiguration.cs new file mode 100644 index 00000000..fa3fb4ed --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ApiConfiguration.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Configuration +{ + [DataContract] + public class ApiConfiguration + { + [DataMember( Name = "images" )] + public ImageConfiguration Images { get; private set; } + + [DataMember( Name = "change_keys" )] + public IReadOnlyList ChangeKeys { get; private set; } + + public override string ToString() + { + if( !string.IsNullOrWhiteSpace( Images?.RootUrl ) ) + { + return Images.RootUrl; + } + + return "not set"; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ApiConfigurationRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ApiConfigurationRequest.cs new file mode 100644 index 00000000..c30d7398 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ApiConfigurationRequest.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.Shims; + +namespace DM.MovieApi.MovieDb.Configuration +{ + internal class ApiConfigurationRequest : ApiRequestBase, IApiConfigurationRequest + { + [ImportingConstructor] + public ApiConfigurationRequest( IApiSettings settings ) + : base( settings ) + { } + + public async Task> GetAsync() + { + ApiQueryResponse response = await base.QueryAsync( "configuration" ); + + return response; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/IApiConfigurationRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/IApiConfigurationRequest.cs new file mode 100644 index 00000000..eea30872 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/IApiConfigurationRequest.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; + +namespace DM.MovieApi.MovieDb.Configuration +{ + /// + /// Interface for retrieving themoviedb.org configuration information. + /// + public interface IApiConfigurationRequest : IApiRequest + { + /// + /// Get themoviedb.org system wide configuration information. Some elements of themoviedb.org + /// API require knowledge of the configuration data. The purpose of the + /// is to try and keep the actual API responses as light as possible. + /// It is recommended you cache this data within your application and check for updates every few days. + /// This method currently holds the data relevant to building image URLs as well as the change key map. + /// + Task> GetAsync(); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ImageConfiguration.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ImageConfiguration.cs new file mode 100644 index 00000000..0cec007f --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Configuration/ImageConfiguration.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Configuration +{ + [DataContract] + public class ImageConfiguration + { + [DataMember( Name = "base_url" )] + public string RootUrl { get; private set; } + + [DataMember( Name = "secure_base_url" )] + public string SecureRootUrl { get; private set; } + + [DataMember( Name = "backdrop_sizes" )] + public IReadOnlyList BackDrops { get; private set; } + + [DataMember( Name = "logo_sizes" )] + public IReadOnlyList Logos { get; private set; } + + [DataMember( Name = "poster_sizes" )] + public IReadOnlyList Posters { get; private set; } + + [DataMember( Name = "profile_sizes" )] + public IReadOnlyList Profiles { get; private set; } + + [DataMember( Name = "still_sizes" )] + public IReadOnlyList Stills { get; private set; } + + public override string ToString() + { + if( !string.IsNullOrWhiteSpace( RootUrl ) ) + { + return RootUrl; + } + + return "not set"; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Country.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Country.cs new file mode 100644 index 00000000..7c3d3682 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Country.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb +{ + [DataContract] + public class Country : IEqualityComparer + { + [DataMember( Name = "iso_3166_1" )] + public string Iso3166Code { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + public Country( string iso3166Code, string name ) + { + Iso3166Code = iso3166Code; + Name = name; + } + + public override bool Equals( object obj ) + { + if( obj is not Country country ) + { + return false; + } + + return Equals( this, country ); + } + + public bool Equals( Country x, Country y ) + => x != null && y != null && x.Iso3166Code == y.Iso3166Code && x.Name == y.Name; + + public override int GetHashCode() => + GetHashCode( this ); + + public int GetHashCode( Country obj ) + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + obj.Iso3166Code.GetHashCode(); + hash = hash * 23 + obj.Name.GetHashCode(); + return hash; + } + } + + public override string ToString() + { + if( string.IsNullOrWhiteSpace( Name ) ) + { + return "n/a"; + } + + return $"{Name} ({Iso3166Code})"; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/ApiGenreRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/ApiGenreRequest.cs new file mode 100644 index 00000000..f2ccc031 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/ApiGenreRequest.cs @@ -0,0 +1,155 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.MovieDb.Movies; +using DM.MovieApi.Shims; +using Newtonsoft.Json.Linq; + +namespace DM.MovieApi.MovieDb.Genres +{ + internal class ApiGenreRequest : ApiRequestBase, IApiGenreRequest + { + // ReSharper disable once InconsistentNaming + private static readonly List _allGenres = new(); + + public IReadOnlyList AllGenres + { + get + { + if( _allGenres.Any() == false ) + { + var genres = Task.Run( () => GetAllAsync() ).GetAwaiter().GetResult().Item; + _allGenres.AddRange( genres ); + } + + return _allGenres.AsReadOnly(); + } + } + + [ImportingConstructor] + public ApiGenreRequest( IApiSettings settings ) + : base( settings ) + { } + + public async Task> FindByIdAsync( int genreId, string language = "en" ) + { + var param = new Dictionary + { + {"language", language} + }; + + string command = $"genre/{genreId}"; + + ApiQueryResponse response = await base.QueryAsync( command, param ); + + EnsureAllGenres( response ); + + return response; + } + + public async Task>> GetAllAsync( string language = "en" ) + { + ApiQueryResponse> tv = await GetTelevisionAsync( language ); + if( tv.Error != null ) + { + return tv; + } + + ApiQueryResponse> movies = await GetMoviesAsync( language ); + if( movies.Error != null ) + { + return movies; + } + + List merged = movies.Item + .Union( tv.Item ) + .OrderBy( x => x.Name ) + .ToList(); + + movies.Item = merged.AsReadOnly(); + + return movies; + } + + public async Task>> GetMoviesAsync( string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + }; + + ApiQueryResponse> genres = await base.QueryAsync( "genre/movie/list", param, GenreDeserializer ); + + return genres; + } + + public async Task>> GetTelevisionAsync( string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + }; + + ApiQueryResponse> genres = await base.QueryAsync( "genre/tv/list", param, GenreDeserializer ); + + return genres; + } + + public async Task> FindMoviesByIdAsync( int genreId, int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + {"include_adult", "false"}, + }; + + string command = $"genre/{genreId}/movies"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + if( response.Error != null ) + { + return response; + } + + response.Results.PopulateGenres( this ); + + return response; + } + + internal void ClearAllGenres() + => _allGenres.Clear(); + + private void EnsureAllGenres( ApiQueryResponse response ) + { + if( response.Error != null ) + { + return; + } + + if( response.Item == null ) + { + return; + } + + if( _allGenres.Contains( response.Item ) == false ) + { + _allGenres.Add( response.Item ); + } + } + + private IReadOnlyList GenreDeserializer( string json ) + { + var obj = JObject.Parse( json ); + + var arr = ( JArray )obj["genres"]; + + // ReSharper disable once PossibleNullReferenceException + var genres = arr.ToObject>(); + + return genres; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/Genre.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/Genre.cs new file mode 100644 index 00000000..2ab6c10b --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/Genre.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Genres +{ + [DataContract] + public class Genre : IEqualityComparer + { + [DataMember( Name = "id" )] + public int Id { get; private set; } + + [DataMember( Name = "name" )] + public string Name { get; private set; } + + public Genre( int id, string name ) + { + Id = id; + Name = name; + } + + public override bool Equals( object obj ) + { + if( obj is not Genre genre ) + { + return false; + } + + return Equals( this, genre ); + } + + public bool Equals( Genre x, Genre y ) + => x != null && y != null && x.Id == y.Id && x.Name == y.Name; + + public override int GetHashCode() + => GetHashCode( this ); + + public int GetHashCode( Genre obj ) + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + obj.Id.GetHashCode(); + hash = hash * 23 + obj.Name.GetHashCode(); + return hash; + } + } + + public override string ToString() + => $"{Name} ({Id})"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/GenreFactory.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/GenreFactory.cs new file mode 100644 index 00000000..a8a1077c --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/GenreFactory.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +// ReSharper disable UnusedMember.Global + +namespace DM.MovieApi.MovieDb.Genres +{ + public static class GenreFactory + { + public static Genre Action() + => new( 28, "Action" ); + + public static Genre Adventure() + => new( 12, "Adventure" ); + + public static Genre ActionAndAdventure() + => new( 10759, "Action & Adventure" ); + + public static Genre Animation() + => new( 16, "Animation" ); + + public static Genre Comedy() + => new( 35, "Comedy" ); + + public static Genre Crime() + => new( 80, "Crime" ); + + public static Genre Drama() + => new( 18, "Drama" ); + + public static Genre Documentary() + => new( 99, "Documentary" ); + + public static Genre Family() + => new( 10751, "Family" ); + + public static Genre Fantasy() + => new( 14, "Fantasy" ); + + public static Genre History() + => new( 36, "History" ); + + public static Genre Horror() + => new( 27, "Horror" ); + + public static Genre Kids() + => new( 10762, "Kids" ); + + public static Genre Music() + => new( 10402, "Music" ); + + public static Genre Mystery() + => new( 9648, "Mystery" ); + + public static Genre News() + => new( 10763, "News" ); + + public static Genre Reality() + => new( 10764, "Reality" ); + + public static Genre Romance() + => new( 10749, "Romance" ); + + public static Genre ScienceFiction() + => new( 878, "Science Fiction" ); + + public static Genre SciFiAndFantasy() + => new( 10765, "Sci-Fi & Fantasy" ); + + public static Genre Soap() + => new( 10766, "Soap" ); + + public static Genre Talk() + => new( 10767, "Talk" ); + + public static Genre Thriller() + => new( 53, "Thriller" ); + + public static Genre TvMovie() + => new( 10770, "TV Movie" ); + + public static Genre War() + => new( 10752, "War" ); + + public static Genre WarAndPolitics() + => new( 10768, "War & Politics" ); + + public static Genre Western() + => new( 37, "Western" ); + + public static IReadOnlyList GetAll() + => LazyAll.Value; + + + private static readonly Lazy> LazyAll = new( () => + { + var all = typeof( GenreFactory ) + .GetTypeInfo() + .DeclaredMethods + .Where( x => x.IsStatic ) + .Where( x => x.IsPublic ) + .Where( x => x.ReturnType == typeof( Genre ) ) + .Select( x => ( Genre )x.Invoke( null, null ) ) + .ToList(); + + return all.AsReadOnly(); + } ); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/GenreIdCollectionMappingExtensions.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/GenreIdCollectionMappingExtensions.cs new file mode 100644 index 00000000..71027dcb --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/GenreIdCollectionMappingExtensions.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using DM.MovieApi.MovieDb.Movies; +using DM.MovieApi.MovieDb.People; +using DM.MovieApi.MovieDb.TV; + +namespace DM.MovieApi.MovieDb.Genres +{ + internal static class GenreIdCollectionMappingExtensions + { + public static void PopulateGenres( this IEnumerable movies, IApiGenreRequest api ) + { + foreach( MovieInfo movie in movies ) + { + movie.Genres = MapGenreIdsToGenres( movie.GenreIds, api ); + } + } + + public static void PopulateGenres( this IEnumerable tvShows, IApiGenreRequest api ) + { + foreach( TVShowInfo tvShow in tvShows ) + { + tvShow.Genres = MapGenreIdsToGenres( tvShow.GenreIds, api ); + } + } + + public static void PopulateGenres( this IEnumerable people, IApiGenreRequest api ) + { + foreach( PersonInfo person in people ) + { + foreach( PersonInfoRole role in person.KnownFor ) + { + role.Genres = MapGenreIdsToGenres( role.GenreIds, api ); + } + } + } + + private static IReadOnlyList MapGenreIdsToGenres( IEnumerable genreIds, IApiGenreRequest api ) + { + IReadOnlyList genres = genreIds + .Select( x => MapGenre( x, api ) ) + .ToList() + .AsReadOnly(); + + return genres; + } + + private static Genre MapGenre( int genreId, IApiGenreRequest api ) + { + Genre genre = api.AllGenres.FirstOrDefault( x => x.Id == genreId ); + + if( genre == null ) + { + genre = Task.Run( () => api.FindByIdAsync( genreId ) ).GetAwaiter().GetResult().Item; + } + + return genre; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/IApiGenreRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/IApiGenreRequest.cs new file mode 100644 index 00000000..b756aaea --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Genres/IApiGenreRequest.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.MovieDb.Movies; + +namespace DM.MovieApi.MovieDb.Genres +{ + /// + /// Interface representing Movie and TV genres. + /// + public interface IApiGenreRequest : IApiRequest + { + /// + /// Provides a cache of all the genres (language='en') returned from . + /// As the Genres do not change much, if any, the cache is never evicted. + /// + IReadOnlyList AllGenres { get; } + + /// + /// Gets all the information about a specific Genre. + /// + /// The genre Id is typically found from a more generic Movie or TV query. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> FindByIdAsync( int genreId, string language = "en" ); + + /// + /// It is recommended to use the property, unless a + /// language specific parameter other than 'en' is provided. + /// + /// themoviedb.org api mixes tv and movie genres into their movies and tv titles. + /// Use this method to ensure all genres are accounted for when attempting to join + /// on Genre.Id from a search result; by default, search results only contain genre + /// id and excludes the name. + /// + /// + /// In some rare cases, a genre is not included in the movie or tv genres list; when this + /// occurs, use the method to find a matching genre. + /// + /// + /// The merged set of Movie and TV Genres. + Task>> GetAllAsync( string language = "en" ); + + /// + /// Gets all movie related Genres. + /// + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task>> GetMoviesAsync( string language = "en" ); + + /// + /// Gets all tv related Genres. + /// + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task>> GetTelevisionAsync( string language = "en" ); + + /// + /// Finds all movies related to a genre, where the Id passed to this method is a genre Id, not a movie Id. + /// + /// The genre Id is typically found through from a related Movie request or from any of the Genre API methods. + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> FindMoviesByIdAsync( int genreId, int pageNumber = 1, string language = "en" ); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/ApiProfessionRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/ApiProfessionRequest.cs new file mode 100644 index 00000000..a010c244 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/ApiProfessionRequest.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.Shims; +using Newtonsoft.Json.Linq; + +namespace DM.MovieApi.MovieDb.IndustryProfessions +{ + internal class ApiProfessionRequest : ApiRequestBase, IApiProfessionRequest + { + [ImportingConstructor] + public ApiProfessionRequest( IApiSettings settings ) + : base( settings ) + { } + + public Task>> GetAllAsync() + { + const string command = "job/list"; + + Task>> response = base.QueryAsync( command, ProfessionDeserializer ); + + return response; + } + + private IReadOnlyList ProfessionDeserializer( string json ) + { + var obj = JObject.Parse( json ); + + var arr = ( JArray )obj["jobs"]; + + // ReSharper disable once PossibleNullReferenceException + var professions = arr.ToObject>(); + + return professions; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/IApiProfessionRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/IApiProfessionRequest.cs new file mode 100644 index 00000000..e83f1e6f --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/IApiProfessionRequest.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; + +namespace DM.MovieApi.MovieDb.IndustryProfessions +{ + /// + /// Interface for retrieving information about Movie/TV industry specific professions. + /// + public interface IApiProfessionRequest : IApiRequest + { + /// + /// Gets all the Movie/TV industry specific professions. + /// + Task>> GetAllAsync(); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/Profession.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/Profession.cs new file mode 100644 index 00000000..813bb5c5 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/IndustryProfessions/Profession.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.IndustryProfessions +{ + [DataContract] + public class Profession + { + [DataMember( Name = "department" )] + public string Department { get; set; } + + [DataMember( Name = "jobs" )] + public IReadOnlyList Jobs { get; set; } + + public override string ToString() + => $"{Department} {Jobs.Count} jobs"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Keywords/Keyword.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Keywords/Keyword.cs new file mode 100644 index 00000000..73cd10d1 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Keywords/Keyword.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Keywords +{ + [DataContract] + public class Keyword : IEqualityComparer + { + /// + /// The keyword Id as identified by theMovieDB.org. + /// + [DataMember( Name = "id" )] + public int Id { get; set; } + + /// + /// The keyword. + /// + [DataMember( Name = "name" )] + public string Name { get; set; } + + public Keyword( int id, string name ) + { + Id = id; + Name = name; + } + + public override bool Equals( object obj ) + { + if( obj is not Keyword genre ) + { + return false; + } + + return Equals( this, genre ); + } + + public bool Equals( Keyword x, Keyword y ) + => x != null && y != null && x.Id == y.Id && x.Name == y.Name; + + public override int GetHashCode() + => GetHashCode( this ); + + public int GetHashCode( Keyword obj ) + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + obj.Id.GetHashCode(); + hash = hash * 23 + obj.Name.GetHashCode(); + return hash; + } + } + + public override string ToString() + => $"{Name} ({Id})"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Keywords/KeywordConverter.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Keywords/KeywordConverter.cs new file mode 100644 index 00000000..a30773e9 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Keywords/KeywordConverter.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace DM.MovieApi.MovieDb.Keywords +{ + /// + /// Expected parent json node is "keywords". The child node is variable + /// and should be set as a parameter to the JsonConverter attribute which + /// will use the KeywordConverter .ctor to create the converter with the + /// provided parameter. + /// + internal class KeywordConverter : JsonConverter + { + private readonly string _key; + + public KeywordConverter( string key ) + { + _key = key; + } + + public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) + { + throw new NotImplementedException(); + } + + public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) + { + JToken obj = JToken.Load( reader ); + + var arr = ( JArray )obj[_key]; + + // ReSharper disable once PossibleNullReferenceException + var keywords = arr.ToObject>(); + + return keywords; + } + + public override bool CanConvert( Type objectType ) + => false; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Language.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Language.cs new file mode 100644 index 00000000..a3fe94ed --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Language.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb +{ + [DataContract] + public class Language : IEqualityComparer + { + [DataMember( Name = "iso_639_1" )] + public string Iso639Code { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + public Language( string iso639Code, string name ) + { + Iso639Code = iso639Code; + Name = name; + } + + public override bool Equals( object obj ) + { + if( obj is not Language language ) + { + return false; + } + + return Equals( this, language ); + } + + public bool Equals( Language x, Language y ) + => x != null && y != null && x.Iso639Code == y.Iso639Code && x.Name == y.Name; + + public override int GetHashCode() + => GetHashCode( this ); + + public int GetHashCode( Language obj ) + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + obj.Iso639Code.GetHashCode(); + hash = hash * 23 + obj.Name.GetHashCode(); + return hash; + } + } + + public override string ToString() + { + if( string.IsNullOrWhiteSpace( Name ) ) + { + return "n/a"; + } + + return $"{Name} ({Iso639Code})"; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/ApiMovieRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/ApiMovieRequest.cs new file mode 100644 index 00000000..e7a1d604 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/ApiMovieRequest.cs @@ -0,0 +1,160 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.MovieDb.Genres; +using DM.MovieApi.Shims; + +namespace DM.MovieApi.MovieDb.Movies +{ + internal class ApiMovieRequest : ApiRequestBase, IApiMovieRequest + { + private readonly IApiGenreRequest _genreApi; + + [ImportingConstructor] + public ApiMovieRequest( IApiSettings settings, IApiGenreRequest genreApi ) + : base( settings ) + { + _genreApi = genreApi; + } + + public async Task> FindByIdAsync( int movieId, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + {"append_to_response", "keywords"}, + }; + + string command = $"movie/{movieId}"; + + ApiQueryResponse response = await base.QueryAsync( command, param ); + + return response; + } + + public async Task> SearchByTitleAsync( string query, int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + {"query", query}, + {"include_adult", "false"}, + {"language", language}, + }; + + const string command = "search/movie"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + if( response.Error != null ) + { + return response; + } + + response.Results.PopulateGenres( _genreApi ); + + return response; + } + + public async Task> GetLatestAsync( string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + {"append_to_response", "keywords"}, + }; + + const string command = "movie/latest"; + + ApiQueryResponse response = await base.QueryAsync( command, param ); + + return response; + } + + public async Task> GetNowPlayingAsync( int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + {"append_to_response", "keywords"}, + }; + + const string command = "movie/now_playing"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + return response; + } + + public async Task> GetUpcomingAsync( int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + {"append_to_response", "keywords"}, + }; + + const string command = "movie/upcoming"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + return response; + } + + public async Task> GetTopRatedAsync( int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + }; + + const string command = "movie/top_rated"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + if( response.Error != null ) + { + return response; + } + + response.Results.PopulateGenres( _genreApi ); + + return response; + } + + public async Task> GetPopularAsync( int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + }; + + const string command = "movie/popular"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + if( response.Error != null ) + { + return response; + } + + response.Results.PopulateGenres( _genreApi ); + + return response; + } + + public async Task> GetCreditsAsync( int movieId, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + }; + + string command = $"movie/{movieId}/credits"; + + ApiQueryResponse response = await base.QueryAsync( command, param ); + + return response; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/IApiMovieRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/IApiMovieRequest.cs new file mode 100644 index 00000000..f919d5a7 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/IApiMovieRequest.cs @@ -0,0 +1,68 @@ +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; + +namespace DM.MovieApi.MovieDb.Movies +{ + /// + /// Interface for retrieving information about Movies. + /// + public interface IApiMovieRequest : IApiRequest + { + /// + /// Gets all the information about a specific Movie. + /// + /// The movie Id is typically found from a more generic Movie query. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> FindByIdAsync( int movieId, string language = "en" ); + + /// + /// Searches for Movies by title. + /// + /// The query to search for Movies. + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> SearchByTitleAsync( string query, int pageNumber = 1, string language = "en" ); + + /// + /// Gets the most recent movie that has been added to TheMovieDb.org. + /// + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetLatestAsync( string language = "en" ); + + /// + /// Gets the list of movies playing that have been, or are being released this week. + /// + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetNowPlayingAsync( int pageNumber = 1, string language = "en" ); + + /// + /// Gets the list of upcoming movies by release date. + /// + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetUpcomingAsync( int pageNumber = 1, string language = "en" ); + + /// + /// Gets the list of top rated movies which is refreshed daily. + /// + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetTopRatedAsync( int pageNumber = 1, string language = "en" ); + + /// + /// Gets the list of popular movies which is refreshed daily. + /// + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetPopularAsync( int pageNumber = 1, string language = "en" ); + + /// + /// Get the cast and crew information for a specific movie id. + /// + /// The movie Id is typically found from a more generic Movie query. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetCreditsAsync( int movieId, string language = "en" ); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/Movie.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/Movie.cs new file mode 100644 index 00000000..4dc1f84f --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/Movie.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using DM.MovieApi.MovieDb.Collections; +using DM.MovieApi.MovieDb.Companies; +using DM.MovieApi.MovieDb.Genres; +using DM.MovieApi.MovieDb.Keywords; +using Newtonsoft.Json; + +namespace DM.MovieApi.MovieDb.Movies +{ + [DataContract] + public class Movie + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "title" )] + public string Title { get; set; } + + [DataMember( Name = "adult" )] + public bool IsAdultThemed { get; set; } + + [DataMember( Name = "backdrop_path" )] + public string BackdropPath { get; set; } + + [DataMember( Name = "belongs_to_collection" )] + public CollectionInfo MovieCollectionInfo { get; set; } + + [DataMember( Name = "budget" )] + public int Budget { get; set; } + + [DataMember( Name = "genres" )] + public IReadOnlyList Genres { get; set; } + + [DataMember( Name = "homepage" )] + public string Homepage { get; set; } + + [DataMember( Name = "imdb_id" )] + public string ImdbId { get; set; } + + /// + /// ISO 3166-1 code. + /// + [DataMember( Name = "original_language" )] + public string OriginalLanguage { get; set; } + + [DataMember( Name = "original_title" )] + public string OriginalTitle { get; set; } + + [DataMember( Name = "overview" )] + public string Overview { get; set; } + + [DataMember( Name = "popularity" )] + public double Popularity { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + + [DataMember( Name = "production_companies" )] + public IReadOnlyList ProductionCompanies { get; set; } + + [DataMember( Name = "production_countries" )] + public IReadOnlyList ProductionCountries { get; set; } + + [DataMember( Name = "release_date" )] + public DateTime ReleaseDate { get; set; } + + [DataMember( Name = "revenue" )] + public decimal Revenue { get; set; } + + [DataMember( Name = "runtime" )] + public int Runtime { get; set; } + + [DataMember( Name = "spoken_languages" )] + public IReadOnlyList SpokenLanguages { get; set; } + + [DataMember( Name = "status" )] + public string Status { get; set; } + + [DataMember( Name = "tagline" )] + public string Tagline { get; set; } + + [DataMember( Name = "video" )] + public bool IsVideo { get; set; } + + [DataMember( Name = "vote_average" )] + public double VoteAverage { get; set; } + + [DataMember( Name = "vote_count" )] + public int VoteCount { get; set; } + + [DataMember( Name = "keywords" )] + [JsonConverter( typeof( KeywordConverter ), "keywords" )] + public IReadOnlyList Keywords { get; set; } + + public Movie() + { + Genres = Array.Empty(); + Keywords = Array.Empty(); + ProductionCompanies = Array.Empty(); + ProductionCountries = Array.Empty(); + SpokenLanguages = Array.Empty(); + } + + public override string ToString() + => $"{Title} ({ReleaseDate:yyyy-MM-dd}) [{Id}]"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/MovieCredit.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/MovieCredit.cs new file mode 100644 index 00000000..11fa133a --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/MovieCredit.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.Movies +{ + [DataContract] + public class MovieCredit + { + [DataMember( Name = "id" )] + public int MovieId { get; set; } + + [DataMember( Name = "cast" )] + public IReadOnlyList CastMembers { get; set; } + + [DataMember( Name = "crew" )] + public IReadOnlyList CrewMembers { get; set; } + } + + [DataContract] + public class MovieCastMember + { + [DataMember( Name = "id" )] + public int PersonId { get; set; } + + [DataMember( Name = "cast_id" )] + public int CastId { get; set; } + + [DataMember( Name = "credit_id" )] + public string CreditId { get; set; } + + [DataMember( Name = "character" )] + public string Character { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "order" )] + public int Order { get; set; } + + [DataMember( Name = "profile_path" )] + public string ProfilePath { get; set; } + + public override string ToString() + => $"{Character}: {Name}"; + } + + [DataContract] + public class MovieCrewMember + { + [DataMember( Name = "id" )] + public int PersonId { get; set; } + + [DataMember( Name = "credit_id" )] + public string CreditId { get; set; } + + [DataMember( Name = "department" )] + public string Department { get; set; } + + [DataMember( Name = "job" )] + public string Job { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "profile_path" )] + public string ProfilePath { get; set; } + + public override string ToString() + => $"{Name} | {Department} | {Job}"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/MovieInfo.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/MovieInfo.cs new file mode 100644 index 00000000..bca1e1fd --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/Movies/MovieInfo.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using DM.MovieApi.MovieDb.Genres; + +namespace DM.MovieApi.MovieDb.Movies +{ + [DataContract] + public class MovieInfo + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "title" )] + public string Title { get; set; } + + [DataMember( Name = "adult" )] + public bool IsAdultThemed { get; set; } + + [DataMember( Name = "backdrop_path" )] + public string BackdropPath { get; set; } + + [DataMember( Name = "genre_ids" )] + internal IReadOnlyList GenreIds { get; set; } + + public IReadOnlyList Genres { get; set; } + + [DataMember( Name = "original_title" )] + public string OriginalTitle { get; set; } + + [DataMember( Name = "overview" )] + public string Overview { get; set; } + + [DataMember( Name = "release_date" )] + public DateTime ReleaseDate { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + + [DataMember( Name = "popularity" )] + public double Popularity { get; set; } + + [DataMember( Name = "video" )] + public bool Video { get; set; } + + [DataMember( Name = "vote_average" )] + public double VoteAverage { get; set; } + + [DataMember( Name = "vote_count" )] + public int VoteCount { get; set; } + + public MovieInfo() + { + GenreIds = Array.Empty(); + Genres = Array.Empty(); + } + + public override string ToString() + => $"{Title} ({Id} - {ReleaseDate:yyyy-MM-dd})"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/ApiPeopleRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/ApiPeopleRequest.cs new file mode 100644 index 00000000..f0b94696 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/ApiPeopleRequest.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.MovieDb.Genres; +using DM.MovieApi.Shims; + +namespace DM.MovieApi.MovieDb.People +{ + internal class ApiPeopleRequest : ApiRequestBase, IApiPeopleRequest + { + private readonly IApiGenreRequest _genreApi; + + [ImportingConstructor] + public ApiPeopleRequest( IApiSettings settings, IApiGenreRequest genreApi ) + : base( settings ) + { + _genreApi = genreApi; + } + + public async Task> FindByIdAsync( int personId, string language = "en" ) + { + var param = new Dictionary + { + {"language", language} + }; + + string command = $"person/{personId}"; + + ApiQueryResponse response = await base.QueryAsync( command, param ); + + return response; + } + + public async Task> SearchByNameAsync( string query, int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + {"query", query}, + {"include_adult", "false"}, + {"language", language}, + }; + + const string command = "search/person"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + if( response.Error != null ) + { + return response; + } + + response.Results.PopulateGenres( _genreApi ); + + return response; + } + + public async Task> GetMovieCreditsAsync( int personId, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + }; + + string command = $"person/{personId}/movie_credits"; + + ApiQueryResponse response = await base.QueryAsync( command, param ); + + return response; + } + + public async Task> GetTVCreditsAsync( int personId, string language = "en" ) + { + var param = new Dictionary + { + {"language", language}, + }; + + string command = $"person/{personId}/tv_credits"; + + ApiQueryResponse response = await base.QueryAsync( command, param ); + + return response; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/Gender.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/Gender.cs new file mode 100644 index 00000000..b49f5126 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/Gender.cs @@ -0,0 +1,9 @@ +namespace DM.MovieApi.MovieDb.People +{ + public enum Gender + { + Unknown = 0, + Female = 1, + Male = 2, + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/IApiPeopleRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/IApiPeopleRequest.cs new file mode 100644 index 00000000..c403666e --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/IApiPeopleRequest.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; + +namespace DM.MovieApi.MovieDb.People +{ + /// + /// Interface for retrieving information about People. + /// + public interface IApiPeopleRequest : IApiRequest + { + /// + /// Gets all the information about a specific Person. + /// + /// The person Id is typically found from a more generic query such as movie or television or search. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> FindByIdAsync( int personId, string language = "en" ); + + /// + /// Searches for People by name. + /// + /// The query to search for People. + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> SearchByNameAsync( string query, int pageNumber = 1, string language = "en" ); + + /// + /// Get the movie credits for a specific person id. Includes movie cast and crew information for the person. + /// + /// The person Id is typically found from a more generic query such as movie or television or search. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetMovieCreditsAsync( int personId, string language = "en" ); + + /// + /// Get the television credits for a specific person id. Includes TV cast and crew information for the person. + /// + /// The person Id is typically found from a more generic query such as movie or television or search. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetTVCreditsAsync( int personId, string language = "en" ); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/Person.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/Person.cs new file mode 100644 index 00000000..5d765be1 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/Person.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.People +{ + [DataContract] + public class Person + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "also_known_as" )] + public IReadOnlyList AlsoKnownAs { get; set; } + + [DataMember( Name = "adult" )] + public bool IsAdultFilmStar { get; set; } + + [DataMember( Name = "biography" )] + public string Biography { get; set; } + + [DataMember( Name = "birthday" )] + public DateTime Birthday { get; set; } + + [DataMember( Name = "deathday" )] + public DateTime? Deathday { get; set; } + + [DataMember( Name = "gender" )] + public Gender Gender { get; set; } + + [DataMember( Name = "homepage" )] + public string Homepage { get; set; } + + [DataMember( Name = "imdb_id" )] + public string ImdbId { get; set; } + + [DataMember( Name = "place_of_birth" )] + public string PlaceOfBirth { get; set; } + + [DataMember( Name = "popularity" )] + public double Popularity { get; set; } + + [DataMember( Name = "profile_path" )] + public string ProfilePath { get; set; } + + public Person() + { + AlsoKnownAs = Array.Empty(); + } + + public override string ToString() + => Name; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonInfo.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonInfo.cs new file mode 100644 index 00000000..ad450b59 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonInfo.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using DM.MovieApi.MovieDb.Genres; + +namespace DM.MovieApi.MovieDb.People +{ + public enum MediaType + { + Unknown, + Movie, + TV, + } + + [DataContract] + public class PersonInfo + { + // TODO: (K. Chase) [2016-07-10] Update all POCO's to explicitly name the Id property, i.e,. PersonId, MovieId, TVShowId. + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "adult" )] + public bool IsAdultFilmStar { get; set; } + + [DataMember( Name = "known_for" )] + public IReadOnlyList KnownFor { get; set; } + + [DataMember( Name = "profile_path" )] + public string ProfilePath { get; set; } + + [DataMember( Name = "popularity" )] + public double Popularity { get; set; } + + public PersonInfo() + { + KnownFor = Array.Empty(); + } + + public override string ToString() + => $"{Name} ({Id})"; + } + + [DataContract] + public class PersonInfoRole + { + // TODO: (K. Chase) [2016-07-10] Break into type for Movie and TV w/ a custom serializer. + // re: see TVShowName v MovieTitle (and related) + + /// + /// The MovieId or TVShowId as defined by the value of . + /// + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "media_type" )] + public MediaType MediaType { get; set; } + + /// + /// Only populated when is TV. + /// + [DataMember( Name = "name" )] + public string TVShowName { get; set; } + + /// + /// Only populated when is TV. + /// + [DataMember( Name = "original_name" )] + public string TVShowOriginalName { get; set; } + + /// + /// Only populated when is Movie. + /// + [DataMember( Name = "title" )] + public string MovieTitle { get; set; } + + /// + /// Only populated when is Movie. + /// + [DataMember( Name = "original_title" )] + public string MovieOriginalTitle { set; get; } + + [DataMember( Name = "backdrop_path" )] + public string BackdropPath { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + + /// + /// Only populated when is Movie. + /// + [DataMember( Name = "release_date" )] + public DateTime MovieReleaseDate { get; set; } + + /// + /// Only populated when is TV. + /// + [DataMember( Name = "first_air_date" )] + public DateTime TVShowFirstAirDate { get; set; } + + [DataMember( Name = "overview" )] + public string Overview { get; set; } + + [DataMember( Name = "adult" )] + public bool IsAdultThemed { get; set; } + + [DataMember( Name = "video" )] + public bool IsVideo { get; set; } + + [DataMember( Name = "genre_ids" )] + internal IReadOnlyList GenreIds { get; set; } + + public IReadOnlyList Genres { get; set; } + + [DataMember( Name = "original_language" )] + public string OriginalLanguage { get; set; } + + [DataMember( Name = "popularity" )] + public double Popularity { get; set; } + + [DataMember( Name = "vote_count" )] + public int VoteCount { get; set; } + + [DataMember( Name = "vote_average" )] + public double VoteAverage { get; set; } + + [DataMember( Name = "origin_country" )] + public IReadOnlyList OriginCountry { get; set; } + + public PersonInfoRole() + { + GenreIds = Array.Empty(); + Genres = Array.Empty(); + OriginCountry = Array.Empty(); + } + + public override string ToString() + { + return MediaType == MediaType.Movie + ? $"Movie: {MovieTitle} ({Id} - {MovieReleaseDate:yyyy-MM-dd})" + : $"TV: {TVShowName} ({Id} - {TVShowFirstAirDate:yyyy-MM-dd})"; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonMovieCredit.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonMovieCredit.cs new file mode 100644 index 00000000..8555a650 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonMovieCredit.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.People +{ + [DataContract] + public class PersonMovieCredit + { + [DataMember( Name = "id" )] + public int PersonId { get; set; } + + [DataMember( Name = "cast" )] + public IReadOnlyList CastRoles { get; set; } + + [DataMember( Name = "crew" )] + public IReadOnlyList CrewRoles { get; set; } + + public PersonMovieCredit() + { + CastRoles = Array.Empty(); + CrewRoles = Array.Empty(); + } + } + + [DataContract] + public class PersonMovieCastMember + { + [DataMember( Name = "id" )] + public int MovieId { get; set; } + + [DataMember( Name = "adult" )] + public bool IsAdultThemed { get; set; } + + [DataMember( Name = "character" )] + public string Character { get; set; } + + [DataMember( Name = "credit_id" )] + public string CreditId { get; set; } + + [DataMember( Name = "original_title" )] + public string OriginalTitle { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + + [DataMember( Name = "release_date" )] + public DateTime ReleaseDate { get; set; } + + [DataMember( Name = "title" )] + public string Title { get; set; } + } + + [DataContract] + public class PersonMovieCrewMember + { + [DataMember( Name = "id" )] + public int MovieId { get; set; } + + [DataMember( Name = "adult" )] + public bool IsAdultThemed { get; set; } + + [DataMember( Name = "credit_id" )] + public string CreditId { get; set; } + + [DataMember( Name = "department" )] + public string Department { get; set; } + + [DataMember( Name = "job" )] + public string Job { get; set; } + + [DataMember( Name = "original_title" )] + public string OriginalTitle { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + + [DataMember( Name = "release_date" )] + public DateTime ReleaseDate { get; set; } + + [DataMember( Name = "title" )] + public string Title { get; set; } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonTVCredit.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonTVCredit.cs new file mode 100644 index 00000000..9587162e --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/People/PersonTVCredit.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.People +{ + [DataContract] + public class PersonTVCredit + { + [DataMember( Name = "id" )] + public int PersonId { get; set; } + + [DataMember( Name = "cast" )] + public IReadOnlyList CastRoles { get; set; } + + [DataMember( Name = "crew" )] + public IReadOnlyList CrewRoles { get; set; } + + public PersonTVCredit() + { + CastRoles = Array.Empty(); + CrewRoles = Array.Empty(); + } + } + + [DataContract] + public class PersonTVCastMember + { + [DataMember( Name = "id" )] + public int TVShowId { get; set; } + + [DataMember( Name = "character" )] + public string Character { get; set; } + + [DataMember( Name = "credit_id" )] + public string CreditId { get; set; } + + [DataMember( Name = "episode_count" )] + public int EpisodeCount { get; set; } + + [DataMember( Name = "first_air_date" )] + public DateTime FirstAirDate { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "original_name" )] + public string OriginalName { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + } + + [DataContract] + public class PersonTVCrewMember + { + [DataMember( Name = "id" )] + public int TVShowId { get; set; } + + [DataMember( Name = "credit_id" )] + public string CreditId { get; set; } + + [DataMember( Name = "department" )] + public string Department { get; set; } + + [DataMember( Name = "episode_count" )] + public int EpisodeCount { get; set; } + + [DataMember( Name = "first_air_date" )] + public DateTime FirstAirDate { get; set; } + + [DataMember( Name = "job" )] + public string Job { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "original_name" )] + public string OriginalName { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/ApiTVShowRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/ApiTVShowRequest.cs new file mode 100644 index 00000000..2e69dfbb --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/ApiTVShowRequest.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; +using DM.MovieApi.MovieDb.Genres; +using DM.MovieApi.Shims; + +namespace DM.MovieApi.MovieDb.TV +{ + internal class ApiTVShowRequest : ApiRequestBase, IApiTVShowRequest + { + private readonly IApiGenreRequest _genreApi; + + [ImportingConstructor] + public ApiTVShowRequest( IApiSettings settings, IApiGenreRequest genreApi ) + : base( settings ) + { + _genreApi = genreApi; + } + + public async Task> FindByIdAsync( int tvShowId, string language = "en" ) + { + var param = new Dictionary + { + { "language", language }, + { "append_to_response", "keywords" }, + }; + + string command = $"tv/{tvShowId}"; + + ApiQueryResponse response = await base.QueryAsync( command, param ); + + return response; + } + + public async Task> SearchByNameAsync( string query, int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + { "query", query }, + { "language", language } + }; + + const string command = "search/tv"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + if( response.Error != null ) + { + return response; + } + + response.Results.PopulateGenres( _genreApi ); + + return response; + } + + public async Task> GetLatestAsync( string language = "en" ) + { + var param = new Dictionary + { + { "language", language }, + { "append_to_response", "keywords" }, + }; + + const string command = "tv/latest"; + + ApiQueryResponse response = await base.QueryAsync( command, param ); + + return response; + } + + public async Task> GetTopRatedAsync( int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + { "language", language } + }; + + const string command = "tv/top_rated"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + if( response.Error != null ) + { + return response; + } + + response.Results.PopulateGenres( _genreApi ); + + return response; + } + + public async Task> GetPopularAsync( int pageNumber = 1, string language = "en" ) + { + var param = new Dictionary + { + { "language", language } + }; + + const string command = "tv/popular"; + + ApiSearchResponse response = await base.SearchAsync( command, pageNumber, param ); + + if( response.Error != null ) + { + return response; + } + + response.Results.PopulateGenres( _genreApi ); + + return response; + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/IApiTVShowRequest.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/IApiTVShowRequest.cs new file mode 100644 index 00000000..d2b1c3b8 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/IApiTVShowRequest.cs @@ -0,0 +1,47 @@ +using System.Threading.Tasks; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.ApiResponse; + +namespace DM.MovieApi.MovieDb.TV +{ + /// + /// Interface for retrieving information about TV shows. + /// + public interface IApiTVShowRequest : IApiRequest + { + /// + /// Gets all the information about a specific TV show. + /// + /// The TV show Id which is typically found from a more generic TV show query. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> FindByIdAsync( int tvShowId, string language = "en" ); + + /// + /// Searches for TV shows by title. + /// + /// The query to search for TV shows. + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> SearchByNameAsync( string query, int pageNumber = 1, string language = "en" ); + + /// + /// Gets the latest TV show added to TheMovieDb.org + /// + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetLatestAsync( string language = "en" ); + + /// + /// Gets the list of top rated TV shows which is refreshed daily. + /// + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetTopRatedAsync( int pageNumber = 1, string language = "en" ); + + /// + /// Gets the list of popular TV shows which is refreshed daily. + /// + /// Default is page 1. The page number to retrieve; the will contain the current page returned and the total number of pages available. + /// Default is English. The ISO 639-1 language code to retrieve the result from. + Task> GetPopularAsync( int pageNumber = 1, string language = "en" ); + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/Network.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/Network.cs new file mode 100644 index 00000000..ec9a3030 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/Network.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.TV +{ + [DataContract] + public class Network : IEqualityComparer + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + public Network( int id, string name ) + { + Id = id; + Name = name; + } + + public bool Equals( Network x, Network y ) + => x != null && y != null && x.Id == y.Id && x.Name == y.Name; + + public int GetHashCode( Network obj ) + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + obj.Id.GetHashCode(); + hash = hash * 23 + obj.Name.GetHashCode(); + return hash; + } + } + + public override bool Equals( object obj ) + { + if( obj is not Network network ) + { + return false; + } + + return Equals( this, network ); + } + + public override int GetHashCode() + => GetHashCode( this ); + + public override string ToString() + => $"{Name} ({Id})"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/Season.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/Season.cs new file mode 100644 index 00000000..aeb51fe8 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/Season.cs @@ -0,0 +1,36 @@ +using System; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.TV +{ + [DataContract] + public class Season + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "air_date" )] + public DateTime AirDate { get; set; } + + [DataMember( Name = "episode_count" )] + public int EpisodeCount { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + + [DataMember( Name = "season_number" )] + public int SeasonNumber { get; set; } + + public Season( int id, DateTime airDate, int episodeCount, string posterPath, int seasonNumber ) + { + Id = id; + AirDate = airDate; + EpisodeCount = episodeCount; + PosterPath = posterPath; + SeasonNumber = seasonNumber; + } + + public override string ToString() + => $"({SeasonNumber} - {AirDate:yyyy-MM-dd})"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShow.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShow.cs new file mode 100644 index 00000000..8db76c17 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShow.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using DM.MovieApi.MovieDb.Companies; +using DM.MovieApi.MovieDb.Genres; +using DM.MovieApi.MovieDb.Keywords; +using Newtonsoft.Json; + +namespace DM.MovieApi.MovieDb.TV +{ + [DataContract] + public class TVShow + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "backdrop_path" )] + public string BackdropPath { get; set; } + + [DataMember( Name = "created_by" )] + public IReadOnlyList CreatedBy { get; set; } + + [DataMember( Name = "episode_run_time" )] + public IReadOnlyList EpisodeRunTime { get; set; } + + [DataMember( Name = "first_air_date" )] + public DateTime FirstAirDate { get; set; } + + [DataMember( Name = "genres" )] + public IReadOnlyList Genres { get; set; } + + [DataMember( Name = "homepage" )] + public string Homepage { get; set; } + + [DataMember( Name = "in_production" )] + public bool InProduction { get; set; } + + [DataMember( Name = "languages" )] + public IReadOnlyList Languages { get; set; } + + [DataMember( Name = "last_air_date" )] + public DateTime LastAirDate { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "networks" )] + public IReadOnlyList Networks { get; set; } + + [DataMember( Name = "number_of_episodes" )] + public int NumberOfEpisodes { get; set; } + + [DataMember( Name = "number_of_seasons" )] + public int NumberOfSeasons { get; set; } + + [DataMember( Name = "origin_country" )] + public IReadOnlyList OriginCountry { get; set; } + + [DataMember( Name = "original_language" )] + public string OriginalLanguage { get; set; } + + [DataMember( Name = "original_name" )] + public string OriginalName { get; set; } + + [DataMember( Name = "overview" )] + public string Overview { get; set; } + + [DataMember( Name = "popularity" )] + public double Popularity { get; set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + + [DataMember( Name = "production_companies" )] + public IReadOnlyList ProductionCompanies { get; set; } + + [DataMember( Name = "seasons" )] + public IReadOnlyList Seasons { get; set; } + + [DataMember( Name = "keywords" )] + [JsonConverter( typeof( KeywordConverter ), "results" )] + public IReadOnlyList Keywords { get; set; } + + public TVShow() + { + CreatedBy = Array.Empty(); + EpisodeRunTime = Array.Empty(); + Genres = Array.Empty(); + Languages = Array.Empty(); + Networks = Array.Empty(); + OriginCountry = Array.Empty(); + ProductionCompanies = Array.Empty(); + Seasons = Array.Empty(); + Keywords = Array.Empty(); + } + + public override string ToString() + => $"{Name} ({FirstAirDate:yyyy-MM-dd}) [{Id}]"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShowCreator.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShowCreator.cs new file mode 100644 index 00000000..5625e1c7 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShowCreator.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace DM.MovieApi.MovieDb.TV +{ + [DataContract] + public class TVShowCreator : IEqualityComparer + { + [DataMember( Name = "id" )] + public int Id { get; set; } + + [DataMember( Name = "name" )] + public string Name { get; set; } + + [DataMember( Name = "profile_path" )] + public string ProfilePath { get; set; } + + public TVShowCreator( int id, string name, string profilePath ) + { + Id = id; + Name = name; + ProfilePath = profilePath; + } + + public bool Equals( TVShowCreator x, TVShowCreator y ) + => x != null && y != null && x.Id == y.Id && x.Name == y.Name; + + public int GetHashCode( TVShowCreator obj ) + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + obj.Id.GetHashCode(); + hash = hash * 23 + obj.Name.GetHashCode(); + return hash; + } + } + + public override bool Equals( object obj ) + { + if( obj is not TVShowCreator showCreator ) + { + return false; + } + + return Equals( this, showCreator ); + } + + public override int GetHashCode() + => GetHashCode( this ); + + public override string ToString() + => $"{Name} ({Id})"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShowInfo.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShowInfo.cs new file mode 100644 index 00000000..7b0abfae --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDb/TV/TVShowInfo.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using DM.MovieApi.MovieDb.Genres; +// ReSharper disable UnusedAutoPropertyAccessor.Local + +namespace DM.MovieApi.MovieDb.TV +{ + [DataContract] + public class TVShowInfo + { + [DataMember( Name = "id" )] + public int Id { get; private set; } + + [DataMember( Name = "name" )] + public string Name { get; private set; } + + [DataMember( Name = "original_name" )] + public string OriginalName { get; private set; } + + [DataMember( Name = "poster_path" )] + public string PosterPath { get; set; } + + [DataMember( Name = "backdrop_path" )] + public string BackdropPath { get; set; } + + [DataMember( Name = "popularity" )] + public double Popularity { get; private set; } + + [DataMember( Name = "vote_average" )] + public double VoteAverage { get; private set; } + + [DataMember( Name = "vote_count" )] + public int VoteCount { get; private set; } + + [DataMember( Name = "overview" )] + public string Overview { get; private set; } + + [DataMember( Name = "first_air_date" )] + public DateTime FirstAirDate { get; private set; } + + [DataMember( Name = "origin_country" )] + public IReadOnlyList OriginCountry { get; private set; } + + [DataMember( Name = "genre_ids" )] + internal IReadOnlyList GenreIds { get; set; } + + public IReadOnlyList Genres { get; internal set; } + + [DataMember( Name = "original_language" )] + public string OriginalLanguage { get; private set; } + + public TVShowInfo() + { + OriginCountry = Array.Empty(); + GenreIds = Array.Empty(); + Genres = Array.Empty(); + } + + public override string ToString() + => $"{Name} ({Id} - {FirstAirDate:yyyy-MM-dd})"; + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDbFactory.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDbFactory.cs new file mode 100644 index 00000000..dfd24173 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/MovieDbFactory.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using DM.MovieApi.ApiRequest; +using DM.MovieApi.MovieDb.Genres; +using DM.MovieApi.Shims; + +[assembly: InternalsVisibleTo( "DM.MovieApi.IntegrationTests" )] + +namespace DM.MovieApi +{ + /// + /// Note: one of the RegisterSettings must be called before the Factory can Create anything. + /// + public static class MovieDbFactory + { + /// + public const string TheMovieDbApiUrl = "http://api.themoviedb.org/3/"; + + /// + /// Determines if the underlying factory has been created. + /// + public static bool IsFactoryComposed => Settings != null; + + internal static IApiSettings Settings { get; private set; } + + /// + /// Registers themoviedb.org settings for use with the internal DI container. + /// + /// + /// + /// + public static void RegisterSettings( string bearerToken ) + { + ResetFactory(); + + if( bearerToken is null || bearerToken.Length <= 200 ) + { + // v3 access key was approx 33 chars; v4 bearer is approx 212 chars. + throw new ArgumentException( + $"Must provide a valid TheMovieDb.org Bearer token. Invalid: {bearerToken}. " + + "A valid token can be found in your account page, under the API section. " + + "You will see a new key listed under the header \"API Read Access Token\".", bearerToken ); + } + + Settings = new MovieDbSettings( TheMovieDbApiUrl, bearerToken ); + } + + /// + /// Creates the specific API requested. + /// + /// + public static Lazy Create() where T : IApiRequest + { + ContainerGuard(); + + var requestResolver = new ApiRequestResolver(); + + return new Lazy( requestResolver.Get ); + } + + /// + /// Creates a global instance exposing all API interfaces against themoviedb.org + /// that are currently available in this release. Each API is exposed via a Lazy property + /// ensuring no objects are created until they are needed. + /// + /// + public static IMovieDbApi GetAllApiRequests() + { + ContainerGuard(); + + // Note: the concrete implementation is currently excluded from the .csproj, but is still included in source control. + + string msg = $"{nameof( GetAllApiRequests )} has been temporarily disabled due to porting the code base to Asp.Net Core to provide support for portable library projects."; + throw new NotImplementedException( msg ); + } + + /// + /// Clears all factory settings; forces the next call to be RegisterSettings. + /// before can be called. + /// + public static void ResetFactory() + { + Settings = null; + } + + private static void ContainerGuard() + { + if( !IsFactoryComposed ) + { + throw new InvalidOperationException( $"{nameof( RegisterSettings )} must be called before the Factory can Create anything." ); + } + } + + private class MovieDbSettings : IApiSettings + { + public string ApiUrl { get; } + public string BearerToken { get; } + + public MovieDbSettings( string apiUrl, string bearerToken ) + { + ApiUrl = apiUrl; + BearerToken = bearerToken; + } + } + + private class ApiRequestResolver + { + private static readonly IReadOnlyDictionary> SupportedDependencyTypeMap; + private static readonly ConcurrentDictionary TypeCtorMap; + + static ApiRequestResolver() + { + SupportedDependencyTypeMap = new Dictionary> + { + {typeof(IApiSettings), () => Settings}, + {typeof(IApiGenreRequest), () => new ApiGenreRequest( Settings )} + }; + + TypeCtorMap = new ConcurrentDictionary(); + } + + public T Get() where T : IApiRequest + { + ConstructorInfo ctor = TypeCtorMap.GetOrAdd( typeof( T ), GetConstructor ); + + ParameterInfo[] param = ctor.GetParameters(); + + if( param.Length == 0 ) + { + return ( T )ctor.Invoke( null ); + } + + var paramObjects = new List( param.Length ); + foreach( ParameterInfo p in param ) + { + if( SupportedDependencyTypeMap.ContainsKey( p.ParameterType ) == false ) + { + throw new InvalidOperationException( $"{p.ParameterType.FullName} is not a supported dependency type for {typeof( T ).FullName}." ); + } + + Func typeResolver = SupportedDependencyTypeMap[p.ParameterType]; + + paramObjects.Add( typeResolver() ); + } + + return ( T )ctor.Invoke( paramObjects.ToArray() ); + } + + private ConstructorInfo GetConstructor( Type t ) + { + ConstructorInfo[] ctors = GetAvailableConstructors( t.GetTypeInfo() ); + + if( ctors.Length == 0 ) + { + throw new InvalidOperationException( $"No public constructors found for {t.FullName}." ); + } + + if( ctors.Length == 1 ) + { + return ctors[0]; + } + + var importingCtors = ctors + .Where( x => x.IsDefined( typeof( ImportingConstructorAttribute ) ) ) + .ToArray(); + + if( importingCtors.Length != 1 ) + { + throw new InvalidOperationException( "Multiple public constructors found. " + + $"One must be decorated with the {nameof( ImportingConstructorAttribute )}." ); + } + + return importingCtors[0]; + } + + private ConstructorInfo[] GetAvailableConstructors( TypeInfo typeInfo ) + { + TypeInfo[] implementingTypes = typeInfo.Assembly.DefinedTypes + .Where( x => x.IsAbstract == false ) + .Where( x => x.IsInterface == false ) + .Where( typeInfo.IsAssignableFrom ) + .ToArray(); + + if( implementingTypes.Length == 0 ) + { + throw new NotSupportedException( $"{typeInfo.Name} must have a concrete implementation." ); + } + + if( implementingTypes.Length != 1 ) + { + throw new NotSupportedException( $"Requested type: {typeInfo.Name}. " + + "Multiple implementations per request interface is not supported." ); + } + + return implementingTypes[0].DeclaredConstructors.ToArray(); + } + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/Shims/CollectionExtensions.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/Shims/CollectionExtensions.cs new file mode 100644 index 00000000..31bedf08 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/Shims/CollectionExtensions.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace DM.MovieApi.Shims +{ + public static class CollectionExtensions + { + public static IReadOnlyList AsReadOnly( this List list ) + { + return new ReadOnlyCollection( list ); + } + } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/Shims/ImportingConstructorAttribute.cs b/MetaNodes/ThirdParty/TheMovieDbWrapper/Shims/ImportingConstructorAttribute.cs new file mode 100644 index 00000000..c288c0f5 --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/Shims/ImportingConstructorAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace DM.MovieApi.Shims +{ + [AttributeUsage( AttributeTargets.Constructor )] + internal sealed class ImportingConstructorAttribute : Attribute + { } +} diff --git a/MetaNodes/ThirdParty/TheMovieDbWrapper/info b/MetaNodes/ThirdParty/TheMovieDbWrapper/info new file mode 100644 index 00000000..16c20d0c --- /dev/null +++ b/MetaNodes/ThirdParty/TheMovieDbWrapper/info @@ -0,0 +1,7 @@ +This code is written by nCubed and was taken from +https://github.com/nCubed/TheMovieDbWrapper/ +On November 22nd 2021 + +No changes have been done to the code, its just easier to include the code in this DLL instead of having to load it separately. + +See the license for this for more information. \ No newline at end of file diff --git a/Plugin.deps.json b/Plugin.deps.json deleted file mode 100644 index dbbdf7b2..00000000 --- a/Plugin.deps.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETCoreApp,Version=v6.0", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETCoreApp,Version=v6.0": { - "Plugin/1.0.0": { - "runtime": { - "Plugin.dll": {} - } - } - } - }, - "libraries": { - "Plugin/1.0.0": { - "type": "project", - "serviceable": false, - "sha512": "" - } - } -} \ No newline at end of file diff --git a/Plugin.pdb b/Plugin.pdb index 7baf204c8507e5f8fae3cd617017b87719472072..11726bb1715626dfa5027d87b01496df46329ada 100644 GIT binary patch delta 1492 zcmZ9MO>9(E6vzMX&g+{uACF8w1_oQ8!-r^@nSKqeXse}A+9_=+ZLm@$w%{NQ(AsvI zI8DkB(S^oEb#$R5&;U)#f?%8-iw0cLgq_r&3wFj37VJnWCi*|q8NJ~p|M$-CoO8d< zz4y(ZyZ-T9JagI&>^Kj+YXd!?J&>9l9s6jCCa%+Gitp$EmS_))-FY-|kYC#aRMnE( z&yJrUS0-HZD^HdWEPc89XU*?{wT_YAzv;%{wyQqR2Ed?QFL_imH9(yM8uEd+37e>K ziv5Cf!bWNrrKl20I&g`;{$saCT6a_aT+n#W$ONz>5JIfVYGRGbMY#A_2})xYwop5%JyZj=FXqOvn2lu2gNdq` z7qc-R2P{rNz5#p@3*bTSxeBUGglll+*8tQo7}fYzfi1?{Xdj^JSOdF|FBPeOfg9*6 z#-&<~8gr)**YYm|ng1MN21ls9Oz;#2*hy~E_!V-q#!>QX8q47OG?x8*UE>z=8yfHD z_-N4_hnUc+u^hZNHSQi46c-bu zgAR?Q1DT{A@6=f0UEF|TJV;Jx{mYhhYn+h*53}IK29nUDB?$MvzjCYCdN*UL(;^^t-4Q})teSh%wGKAtDnzb{cUcl?pb*4(aWf03_iu<-***3yv z+D4!sEp95RZYQY_%SJN!bDTRocgH!!~~q2D&UGI}xuoN^;-CHyVbOy|MRJ zZ#PfStHVJ*Diqt7DVvp3*sYX}H0|1Tq_4@7 L9cpSf<<9&I>Vv3a delta 1135 zcmZ9LOH30{6o$`qrtS0rkwuXhV{3RB+G!DJi&_wh0tKOJB`$~}HVvrd5g>{S+k}N7 zVF9Kttsz2U6p4$8iIEt~3L*>LVT@^vi3zTV;?jlx9XopCB;U;W&bfE)W9}@EFODoU zq~Du}%2Px+Gtogp9GjZBHaawkkUk+Nv0Pt_J|n)u;*P$^DLh+bxECHyj$MV{TAHtT zJTuz4oYLDc3< zgqGy{&ufv>>ukkGImgaoU;g!f$oXN!gP^cmwB0h|=We5(*jwIIn{TIS;}c zIS;{)ao!3)&Urih1m|bqAlU9SiOs@Gw@0_zT!tJ51%@()RE8pkVunnHe1<#*TLvWtLk2wt10bycl*waA z28yQuW%C%)!Lp?cB@Af{xKV6>Qglc}CJfFY3~nIRiUrZc2Y?q^XK z_hiUpC}t=DisS)hQh{tG1_g$&iTt9xW(;}^24Jo}gWY6%mcY#s%;y*