Skip to content

Commit

Permalink
feat: store tmdb keywords and production countries
Browse files Browse the repository at this point in the history
…because I need them for Shokofin/Jellyfin.
  • Loading branch information
revam committed Nov 25, 2024
1 parent 1f19d95 commit 3c66619
Show file tree
Hide file tree
Showing 15 changed files with 292 additions and 8 deletions.
50 changes: 50 additions & 0 deletions Shoko.Server/API/v3/Controllers/TmdbController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,31 @@ public ActionResult<IReadOnlyList<ContentRating>> GetContentRatingsForTmdbMovieB
return new(movie.ContentRatings.ToDto(language));
}

[HttpGet("Movie/{movieID}/Keywords")]
public ActionResult<IReadOnlyList<string>> GetKeywordsForTmdbMovieByMovieID(
[FromRoute] int movieID
)
{
var movie = RepoFactory.TMDB_Movie.GetByTmdbMovieID(movieID);
if (movie is null)
return NotFound(MovieNotFound);

return movie.Keywords;
}

[HttpGet("Movie/{movieID}/ProductionCountries")]
public ActionResult<IReadOnlyDictionary<string, string>> GetProductionCountriesForTmdbMovieByMovieID(
[FromRoute] int movieID
)
{
var movie = RepoFactory.TMDB_Movie.GetByTmdbMovieID(movieID);
if (movie is null)
return NotFound(MovieNotFound);

return movie.ProductionCountries
.ToDictionary(country => country.CountryCode, country => country.CountryName);
}

#endregion

#region Same-Source Linked Entries
Expand Down Expand Up @@ -1144,6 +1169,31 @@ public ActionResult<IReadOnlyList<ContentRating>> GetContentRatingsForTmdbShowBy
return new(show.ContentRatings.ToDto(language));
}

[HttpGet("Show/{showID}/Keywords")]
public ActionResult<IReadOnlyList<string>> GetKeywordsForTmdbShowByShowID(
[FromRoute] int showID
)
{
var show = RepoFactory.TMDB_Show.GetByTmdbShowID(showID);
if (show is null)
return NotFound(ShowNotFound);

return show.Keywords;
}

[HttpGet("Show/{showID}/ProductionCountries")]
public ActionResult<IReadOnlyDictionary<string, string>> GetProductionCountriesForTmdbShowByShowID(
[FromRoute] int showID
)
{
var show = RepoFactory.TMDB_Show.GetByTmdbShowID(showID);
if (show is null)
return NotFound(ShowNotFound);

return show.ProductionCountries
.ToDictionary(country => country.CountryCode, country => country.CountryName);
}

#endregion

#region Same-Source Linked Entries
Expand Down
19 changes: 19 additions & 0 deletions Shoko.Server/API/v3/Models/TMDB/Movie.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ public class Movie
/// </summary>
public IReadOnlyList<string> Genres { get; init; }

/// <summary>
/// Keywords.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public IReadOnlyList<string>? Keywords { get; init; }

/// <summary>
/// Content ratings for different countries for this show.
/// </summary>
Expand All @@ -113,6 +119,12 @@ public class Movie
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public IReadOnlyList<Studio>? Studios { get; init; }

/// <summary>
/// Production countries.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public IReadOnlyDictionary<string, string>? ProductionCountries { get; init; }

/// <summary>
/// Images associated with the movie, if they should be included.
/// </summary>
Expand Down Expand Up @@ -217,6 +229,11 @@ public Movie(TMDB_Movie movie, IncludeDetails? includeDetails = null, IReadOnlyS
.ToList();
if (include.HasFlag(IncludeDetails.FileCrossReferences))
FileCrossReferences = FileCrossReference.From(movie.FileCrossReferences);
if (include.HasFlag(IncludeDetails.Keywords))
Keywords = movie.Keywords;
if (include.HasFlag(IncludeDetails.ProductionCountries))
ProductionCountries = movie.ProductionCountries
.ToDictionary(country => country.CountryCode, country => country.CountryName);
ReleasedAt = movie.ReleasedAt;
CreatedAt = movie.CreatedAt.ToUniversalTime();
LastUpdatedAt = movie.LastUpdatedAt.ToUniversalTime();
Expand Down Expand Up @@ -356,5 +373,7 @@ public enum IncludeDetails
Studios = 64,
ContentRatings = 128,
FileCrossReferences = 256,
Keywords = 512,
ProductionCountries = 1024,
}
}
19 changes: 19 additions & 0 deletions Shoko.Server/API/v3/Models/TMDB/Show.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ public class Show
/// </summary>
public IReadOnlyList<string> Genres { get; init; }

/// <summary>
/// Keywords.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public IReadOnlyList<string>? Keywords { get; init; }

/// <summary>
/// Content ratings for different countries for this show.
/// </summary>
Expand All @@ -85,6 +91,12 @@ public class Show
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public IReadOnlyList<Studio>? Studios { get; init; }

/// <summary>
/// Production countries.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public IReadOnlyDictionary<string, string>? ProductionCountries { get; init; }

/// <summary>
/// The television networks that aired the show.
/// </summary>
Expand Down Expand Up @@ -240,6 +252,11 @@ public Show(TMDB_Show show, TMDB_AlternateOrdering? alternateOrdering, IncludeDe
.OrderBy(xref => xref.AnidbAnimeID)
.ThenBy(xref => xref.TmdbShowID)
.ToList();
if (include.HasFlag(IncludeDetails.Keywords))
Keywords = show.Keywords;
if (include.HasFlag(IncludeDetails.ProductionCountries))
ProductionCountries = show.ProductionCountries
.ToDictionary(country => country.CountryCode, country => country.CountryName);
FirstAiredAt = show.FirstAiredAt;
LastAiredAt = show.LastAiredAt;
CreatedAt = show.CreatedAt.ToUniversalTime();
Expand Down Expand Up @@ -358,5 +375,7 @@ public enum IncludeDetails
Studios = 128,
Networks = 256,
ContentRatings = 512,
Keywords = 1024,
ProductionCountries = 2048,
}
}
8 changes: 6 additions & 2 deletions Shoko.Server/Databases/MySQL.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace Shoko.Server.Databases;
public class MySQL : BaseDatabase<MySqlConnection>
{
public override string Name { get; } = "MySQL";
public override int RequiredVersion { get; } = 140;
public override int RequiredVersion { get; } = 141;

private List<DatabaseCommand> createVersionTable = new()
{
Expand Down Expand Up @@ -849,7 +849,11 @@ public class MySQL : BaseDatabase<MySqlConnection>
new(139, 10, "ALTER TABLE Trakt_Show ADD COLUMN TmdbShowID INT NULL;"),
new(139, 11, DatabaseFixes.CleanupAfterRemovingTvDB),
new(139, 12, DatabaseFixes.ClearQuartzQueue),
new(140, 1, DatabaseFixes.RepairMissingTMDBPersons)
new(140, 1, DatabaseFixes.RepairMissingTMDBPersons),
new(141, 1, "ALTER TABLE `TMDB_Movie` ADD COLUMN `Keywords` VARCHAR(512) NULL DEFAULT NULL;"),
new(141, 2, "ALTER TABLE `TMDB_Movie` ADD COLUMN `ProductionCountries` VARCHAR(32) NULL DEFAULT NULL;"),
new(141, 3, "ALTER TABLE `TMDB_Show` ADD COLUMN `Keywords` VARCHAR(512) NULL DEFAULT NULL;"),
new(141, 4, "ALTER TABLE `TMDB_Show` ADD COLUMN `ProductionCountries` VARCHAR(32) NULL DEFAULT NULL;"),
};

private DatabaseCommand linuxTableVersionsFix = new("RENAME TABLE versions TO Versions;");
Expand Down
2 changes: 2 additions & 0 deletions Shoko.Server/Databases/NHIbernate/StringListConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destina
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object? value)
=> value switch
{
null => [],
string i => i.Split("|||").ToList(),
List<string> l => l,
_ => throw new ArgumentException($"DestinationType must be {nameof(String)}.")
Expand All @@ -44,6 +45,7 @@ public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destina
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type? destinationType)
=> value switch
{
null => string.Empty,
string i => i,
List<string> l => l.Join("|||"),
_ => throw new ArgumentException($"DestinationType must be {typeof(List<string>).FullName}."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destina
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object? value)
=> value switch
{
null => [],
string i => i.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).Select(s => TMDB_ContentRating.FromString(s)).ToList(),
List<TMDB_ContentRating> l => l,
_ => throw new ArgumentException($"DestinationType must be {nameof(String)}.")
Expand All @@ -44,6 +45,7 @@ public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destina
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type? destinationType)
=> value switch
{
null => string.Empty,
string i => i,
List<TMDB_ContentRating> l => l.Select(r => r.ToString()).Join('|'),
_ => throw new ArgumentException($"DestinationType must be {typeof(List<TMDB_ContentRating>).FullName}."),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.ComponentModel;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;
using System.Data;
using System.Data.Common;
using NHibernate;
using NHibernate.Engine;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Shoko.Server.Extensions;
using Shoko.Server.Models.TMDB;

#nullable enable
namespace Shoko.Server.Databases.NHibernate;

public class TmdbProductionCountryConverter : TypeConverter, IUserType
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type? sourceType)
=> sourceType?.FullName switch
{
nameof(List<TMDB_ProductionCountry>) => true,
nameof(String) => true,
_ => false
};

public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
=> destinationType?.FullName switch
{
nameof(String) => true,
_ => false,
};

public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object? value)
=> value switch
{
null => [],
string i => i.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).Select(s => TMDB_ProductionCountry.FromString(s)).ToList(),
List<TMDB_ProductionCountry> l => l,
_ => throw new ArgumentException($"DestinationType must be {nameof(String)}.")
};

public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type? destinationType)
=> value switch
{
null => string.Empty,
string i => i,
List<TMDB_ProductionCountry> l => l.Select(r => r.ToString()).Join('|'),
_ => throw new ArgumentException($"DestinationType must be {typeof(List<TMDB_ProductionCountry>).FullName}."),
};

public override object CreateInstance(ITypeDescriptorContext? context, IDictionary? propertyValues)
=> true;

#region IUserType Members

public object Assemble(object cached, object owner)
=> DeepCopy(cached);

public object DeepCopy(object value)
=> value;

public object Disassemble(object value)
=> DeepCopy(value);

public int GetHashCode(object x)
=> x == null ? base.GetHashCode() : x.GetHashCode();

public bool IsMutable
=> true;

public object? NullSafeGet(DbDataReader rs, string[] names, ISessionImplementor impl, object owner)
=> ConvertFrom(null, null, NHibernateUtil.String.NullSafeGet(rs, names[0], impl));

public void NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session)
=> ((IDataParameter)cmd.Parameters[index]).Value = value == null ? DBNull.Value : ConvertTo(null, null, value, typeof(List<TMDB_ProductionCountry>));

public object Replace(object original, object target, object owner)
=> original;

public Type ReturnedType
=> typeof(List<TMDB_ProductionCountry>);

public SqlType[] SqlTypes
=> new[] { NHibernateUtil.String.SqlType };

bool IUserType.Equals(object x, object y)
=> ReferenceEquals(x, y) || (x != null && y != null && x.Equals(y));

#endregion
}
8 changes: 6 additions & 2 deletions Shoko.Server/Databases/SQLServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace Shoko.Server.Databases;
public class SQLServer : BaseDatabase<SqlConnection>
{
public override string Name { get; } = "SQLServer";
public override int RequiredVersion { get; } = 132;
public override int RequiredVersion { get; } = 133;

public override void BackupDatabase(string fullfilename)
{
Expand Down Expand Up @@ -779,7 +779,11 @@ public override bool HasVersionsTable()
new DatabaseCommand(131, 10, "ALTER TABLE Trakt_Show ADD TmdbShowID INT NULL;"),
new DatabaseCommand(131, 11, DatabaseFixes.CleanupAfterRemovingTvDB),
new DatabaseCommand(131, 12, DatabaseFixes.ClearQuartzQueue),
new DatabaseCommand(132, 1, DatabaseFixes.RepairMissingTMDBPersons)
new DatabaseCommand(132, 1, DatabaseFixes.RepairMissingTMDBPersons),
new DatabaseCommand(133, 1, "ALTER TABLE TMDB_Movie ADD Keywords NVARCHAR(512) NULL DEFAULT NULL;"),
new DatabaseCommand(133, 2, "ALTER TABLE TMDB_Movie ADD ProductionCountries NVARCHAR(32) NULL DEFAULT NULL;"),
new DatabaseCommand(133, 3, "ALTER TABLE TMDB_Show ADD Keywords NVARCHAR(512) NULL DEFAULT NULL;"),
new DatabaseCommand(133, 4, "ALTER TABLE TMDB_Show ADD ProductionCountries NVARCHAR(32) NULL DEFAULT NULL;"),
};

private static void AlterImdbMovieIDType()
Expand Down
8 changes: 6 additions & 2 deletions Shoko.Server/Databases/SQLite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class SQLite : BaseDatabase<SqliteConnection>
{
public override string Name => "SQLite";

public override int RequiredVersion => 124;
public override int RequiredVersion => 125;

public override void BackupDatabase(string fullfilename)
{
Expand Down Expand Up @@ -774,7 +774,11 @@ public override void CreateDatabase()
new(123, 10, "ALTER TABLE Trakt_Show ADD COLUMN TmdbShowID INTEGER NULL;"),
new(123, 11, DatabaseFixes.CleanupAfterRemovingTvDB),
new(123, 12, DatabaseFixes.ClearQuartzQueue),
new(124, 1, DatabaseFixes.RepairMissingTMDBPersons)
new(124, 1, DatabaseFixes.RepairMissingTMDBPersons),
new(125, 1, "ALTER TABLE TMDB_Movie ADD COLUMN Keywords TEXT NULL DEFAULT NULL;"),
new(125, 2, "ALTER TABLE TMDB_Movie ADD COLUMN ProductionCountries TEXT NULL DEFAULT NULL;"),
new(125, 3, "ALTER TABLE TMDB_Show ADD COLUMN Keywords TEXT NULL DEFAULT NULL;"),
new(125, 4, "ALTER TABLE TMDB_Show ADD COLUMN ProductionCountries TEXT NULL DEFAULT NULL;"),
};

private static Tuple<bool, string> MigrateRenamers(object connection)
Expand Down
2 changes: 2 additions & 0 deletions Shoko.Server/Mappings/TMDB/TMDB_MovieMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ public TMDB_MovieMap()
Map(x => x.IsRestricted).Not.Nullable();
Map(x => x.IsVideo).Not.Nullable();
Map(x => x.Genres).Not.Nullable().CustomType<StringListConverter>();
Map(x => x.Keywords).Not.Nullable().CustomType<StringListConverter>();
Map(x => x.ContentRatings).Not.Nullable().CustomType<TmdbContentRatingConverter>();
Map(x => x.ProductionCountries).Not.Nullable().CustomType<TmdbProductionCountryConverter>();
Map(x => x.RuntimeMinutes).Column("Runtime");
Map(x => x.UserRating).Not.Nullable();
Map(x => x.UserVotes).Not.Nullable();
Expand Down
2 changes: 2 additions & 0 deletions Shoko.Server/Mappings/TMDB/TMDB_ShowMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ public TMDB_ShowMap()
Map(x => x.OriginalLanguageCode).Not.Nullable();
Map(x => x.IsRestricted).Not.Nullable();
Map(x => x.Genres).Not.Nullable().CustomType<StringListConverter>();
Map(x => x.Keywords).Not.Nullable().CustomType<StringListConverter>();
Map(x => x.ContentRatings).Not.Nullable().CustomType<TmdbContentRatingConverter>();
Map(x => x.ProductionCountries).Not.Nullable().CustomType<TmdbProductionCountryConverter>();
Map(x => x.EpisodeCount).Not.Nullable();
Map(x => x.SeasonCount).Not.Nullable();
Map(x => x.AlternateOrderingCount).Not.Nullable();
Expand Down
Loading

0 comments on commit 3c66619

Please sign in to comment.