Merge pull request #11762 from Shadowghost/fix-lyrics

Mark Audio as RequiresDeserialization and backfill data
This commit is contained in:
Joshua M. Boniface 2024-06-01 18:32:36 -04:00 committed by GitHub
commit e2c909f50f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 115 additions and 8 deletions

View File

@ -1298,16 +1298,15 @@ namespace Emby.Server.Implementations.Data
&& type != typeof(Book)
&& type != typeof(LiveTvProgram)
&& type != typeof(AudioBook)
&& type != typeof(Audio)
&& type != typeof(MusicAlbum);
}
private BaseItem GetItem(SqliteDataReader reader, InternalItemsQuery query)
{
return GetItem(reader, query, HasProgramAttributes(query), HasEpisodeAttributes(query), HasServiceName(query), HasStartDate(query), HasTrailerTypes(query), HasArtistFields(query), HasSeriesFields(query));
return GetItem(reader, query, HasProgramAttributes(query), HasEpisodeAttributes(query), HasServiceName(query), HasStartDate(query), HasTrailerTypes(query), HasArtistFields(query), HasSeriesFields(query), false);
}
private BaseItem GetItem(SqliteDataReader reader, InternalItemsQuery query, bool enableProgramAttributes, bool hasEpisodeAttributes, bool hasServiceName, bool queryHasStartDate, bool hasTrailerTypes, bool hasArtistFields, bool hasSeriesFields)
private BaseItem GetItem(SqliteDataReader reader, InternalItemsQuery query, bool enableProgramAttributes, bool hasEpisodeAttributes, bool hasServiceName, bool queryHasStartDate, bool hasTrailerTypes, bool hasArtistFields, bool hasSeriesFields, bool skipDeserialization)
{
var typeString = reader.GetString(0);
@ -1320,7 +1319,7 @@ namespace Emby.Server.Implementations.Data
BaseItem item = null;
if (TypeRequiresDeserialization(type))
if (TypeRequiresDeserialization(type) && !skipDeserialization)
{
try
{
@ -2562,7 +2561,7 @@ namespace Emby.Server.Implementations.Data
foreach (var row in statement.ExecuteQuery())
{
var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields);
var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields, query.SkipDeserialization);
if (item is not null)
{
items.Add(item);
@ -2774,7 +2773,7 @@ namespace Emby.Server.Implementations.Data
foreach (var row in statement.ExecuteQuery())
{
var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields);
var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields, false);
if (item is not null)
{
list.Add(item);
@ -5021,7 +5020,7 @@ AND Type = @InternalPersonType)");
foreach (var row in statement.ExecuteQuery())
{
var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields);
var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields, false);
if (item is not null)
{
var countStartColumn = columns.Count - 1;

View File

@ -44,7 +44,8 @@ namespace Jellyfin.Server.Migrations
typeof(Routines.FixPlaylistOwner),
typeof(Routines.MigrateRatingLevels),
typeof(Routines.AddDefaultCastReceivers),
typeof(Routines.UpdateDefaultPluginRepository)
typeof(Routines.UpdateDefaultPluginRepository),
typeof(Routines.FixAudioData),
};
/// <summary>

View File

@ -0,0 +1,104 @@
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Migrations.Routines
{
/// <summary>
/// Fixes the data column of audio types to be deserializable.
/// </summary>
internal class FixAudioData : IMigrationRoutine
{
private const string DbFilename = "library.db";
private readonly ILogger<FixAudioData> _logger;
private readonly IServerApplicationPaths _applicationPaths;
private readonly IItemRepository _itemRepository;
public FixAudioData(
IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
IItemRepository itemRepository)
{
_applicationPaths = applicationPaths;
_itemRepository = itemRepository;
_logger = loggerFactory.CreateLogger<FixAudioData>();
}
/// <inheritdoc/>
public Guid Id => Guid.Parse("{CF6FABC2-9FBE-4933-84A5-FFE52EF22A58}");
/// <inheritdoc/>
public string Name => "FixAudioData";
/// <inheritdoc/>
public bool PerformOnNewInstall => false;
/// <inheritdoc/>
public void Perform()
{
var dbPath = Path.Combine(_applicationPaths.DataPath, DbFilename);
// Back up the database before modifying any entries
for (int i = 1; ; i++)
{
var bakPath = string.Format(CultureInfo.InvariantCulture, "{0}.bak{1}", dbPath, i);
if (!File.Exists(bakPath))
{
try
{
File.Copy(dbPath, bakPath);
_logger.LogInformation("Library database backed up to {BackupPath}", bakPath);
break;
}
catch (Exception ex)
{
_logger.LogError(ex, "Cannot make a backup of {Library} at path {BackupPath}", DbFilename, bakPath);
throw;
}
}
}
_logger.LogInformation("Backfilling audio lyrics data to database.");
var startIndex = 0;
var records = _itemRepository.GetCount(new InternalItemsQuery
{
IncludeItemTypes = [BaseItemKind.Audio],
});
while (startIndex < records)
{
var results = _itemRepository.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = [BaseItemKind.Audio],
StartIndex = startIndex,
Limit = 100,
SkipDeserialization = true
})
.Cast<Audio>()
.ToList();
foreach (var audio in results)
{
var lyricMediaStreams = audio.GetMediaStreams().Where(s => s.Type == MediaStreamType.Lyric).Select(s => s.Path).ToList();
if (lyricMediaStreams.Count > 0)
{
audio.HasLyrics = true;
audio.LyricFiles = lyricMediaStreams;
}
}
_itemRepository.SaveItems(results, CancellationToken.None);
startIndex += 100;
}
}
}
}

View File

@ -51,6 +51,7 @@ namespace MediaBrowser.Controller.Entities
TrailerTypes = Array.Empty<TrailerType>();
VideoTypes = Array.Empty<VideoType>();
Years = Array.Empty<int>();
SkipDeserialization = false;
}
public InternalItemsQuery(User? user)
@ -358,6 +359,8 @@ namespace MediaBrowser.Controller.Entities
public string? SeriesTimerId { get; set; }
public bool SkipDeserialization { get; set; }
public void SetUser(User user)
{
MaxParentalRating = user.MaxParentalAgeRating;