Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add DB migration & endpoint to download missing TMDB People #1203

Merged
10 changes: 10 additions & 0 deletions Shoko.Server/API/v3/Controllers/TmdbController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1478,6 +1478,16 @@ public async Task<ActionResult> DownloadImagesForTmdbShowByShowID(
return NoContent();
}

/// <summary>
/// Download any missing TMDB Person records.
/// </summary>
[HttpGet("Person/DownloadMissing")]
public ActionResult RepairMissingTmdbPersonRecords()
{
Task.Run(() => _tmdbMetadataService.RepairMissingPersonRecords()).ConfigureAwait(false);
return Ok();
}

#endregion

#region Online (Search / Bulk / Single)
Expand Down
6 changes: 6 additions & 0 deletions Shoko.Server/Databases/DatabaseFixes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -837,4 +837,10 @@ public static void ClearQuartzQueue()
var queueHandler = Utils.ServiceContainer.GetRequiredService<QueueHandler>();
queueHandler.Clear().ConfigureAwait(false).GetAwaiter().GetResult();
}

public static void RepairMissingTMDBPersons()
{
var service = Utils.ServiceContainer.GetRequiredService<TmdbMetadataService>();
service.RepairMissingPersonRecords().ConfigureAwait(false).GetAwaiter().GetResult();
}
}
3 changes: 2 additions & 1 deletion 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; } = 139;
public override int RequiredVersion { get; } = 140;

private List<DatabaseCommand> createVersionTable = new()
{
Expand Down Expand Up @@ -849,6 +849,7 @@ 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)
revam marked this conversation as resolved.
Show resolved Hide resolved
};

private DatabaseCommand linuxTableVersionsFix = new("RENAME TABLE versions TO Versions;");
Expand Down
3 changes: 2 additions & 1 deletion 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; } = 131;
public override int RequiredVersion { get; } = 132;

public override void BackupDatabase(string fullfilename)
{
Expand Down Expand Up @@ -779,6 +779,7 @@ 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)
};

private static void AlterImdbMovieIDType()
Expand Down
3 changes: 2 additions & 1 deletion 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 => 123;
public override int RequiredVersion => 124;

public override void BackupDatabase(string fullfilename)
{
Expand Down Expand Up @@ -774,6 +774,7 @@ 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)
revam marked this conversation as resolved.
Show resolved Hide resolved
};

private static Tuple<bool, string> MigrateRenamers(object connection)
Expand Down
61 changes: 61 additions & 0 deletions Shoko.Server/Providers/TMDB/TmdbMetadataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2031,6 +2031,38 @@ private void PurgeCompany(int companyId, bool removeImageFiles = true)

#region People

public async Task RepairMissingPersonRecords()
{
var missingIds = new HashSet<int>();
var (updateCount, skippedCount) = (0, 0);
fearnlj01 marked this conversation as resolved.
Show resolved Hide resolved

var peopleIds = _tmdbPeople.GetAll().Select(person => person.TmdbPersonID).ToHashSet();

foreach (var person in _tmdbEpisodeCast.GetAll())
if (!peopleIds.Contains(person.TmdbPersonID)) missingIds.Add(person.TmdbPersonID);
foreach (var person in _tmdbEpisodeCrew.GetAll())
if (!peopleIds.Contains(person.TmdbPersonID)) missingIds.Add(person.TmdbPersonID);

foreach (var person in _tmdbMovieCast.GetAll())
if (!peopleIds.Contains(person.TmdbPersonID)) missingIds.Add(person.TmdbPersonID);
foreach (var person in _tmdbMovieCrew.GetAll())
if (!peopleIds.Contains(person.TmdbPersonID)) missingIds.Add(person.TmdbPersonID);

fearnlj01 marked this conversation as resolved.
Show resolved Hide resolved
_logger.LogDebug("Found {@Count} unique missing TMDB Person record(s) for Episode & Movie staff", missingIds.Count);

foreach (var personId in missingIds)
{
var (_, updated) = await UpdatePerson(personId, forceRefresh: true);
if (updated)
updateCount++;
else
skippedCount++;
}

fearnlj01 marked this conversation as resolved.
Show resolved Hide resolved
_logger.LogInformation("Updated missing TMDB People: Found/Updated/Skipped {@Found}/{@Updated}/{@Skipped}",
missingIds.Count, updateCount, skippedCount);
}

public async Task<(bool added, bool updated)> UpdatePerson(int personId, bool forceRefresh = false, bool downloadImages = false)
{
using (await GetLockForEntity(ForeignEntityType.Person, personId, "metadata & images", "Update").ConfigureAwait(false))
Expand All @@ -2048,6 +2080,13 @@ private void PurgeCompany(int companyId, bool removeImageFiles = true)
methods |= PersonMethods.Images;
var newlyAdded = tmdbPerson.TMDB_PersonID is 0;
var person = await UseClient(c => c.GetPersonAsync(personId, methods), $"Get person {personId}");
if (person is null)
{
_logger.LogDebug("Unable to update staff; Refreshing related links. (Person={PersonId})", personId);
// Defer the update to avoid recursively locking the person...
_ = Task.Run(() => UpdateMoviesAndShowsByPerson(personId)).ConfigureAwait(false);
return (newlyAdded, false);
}
var updated = tmdbPerson.Populate(person);
if (updated)
{
Expand All @@ -2061,6 +2100,28 @@ private void PurgeCompany(int companyId, bool removeImageFiles = true)
return (newlyAdded, updated);
}
}

private async Task UpdateMoviesAndShowsByPerson(int tmdbPersonId)
{
var showIds = new HashSet<int>();
var movieIds = new HashSet<int>();

foreach (var staff in _tmdbEpisodeCast.GetByTmdbPersonID(tmdbPersonId))
showIds.Add(staff.TmdbShowID);
foreach (var staff in _tmdbEpisodeCrew.GetByTmdbPersonID(tmdbPersonId))
showIds.Add(staff.TmdbShowID);

foreach (var staff in _tmdbMovieCast.GetByTmdbPersonID(tmdbPersonId))
movieIds.Add(staff.TmdbMovieID);
foreach (var staff in _tmdbMovieCrew.GetByTmdbPersonID(tmdbPersonId))
movieIds.Add(staff.TmdbMovieID);

foreach (var showId in showIds)
await UpdateShow(showId, downloadCrewAndCast: true);
fearnlj01 marked this conversation as resolved.
Show resolved Hide resolved

foreach (var movieId in movieIds)
await UpdateMovie(movieId, downloadCrewAndCast: true);
}

private async Task DownloadPersonImages(int personId, ProfileImages images, bool forceDownload = false)
{
Expand Down