2
0
Эх сурвалжийг харах

Merge pull request #11762 from Shadowghost/fix-lyrics

Mark Audio as RequiresDeserialization and backfill data
Joshua M. Boniface 1 жил өмнө
parent
commit
e2c909f50f

+ 6 - 7
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -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;

+ 2 - 1
Jellyfin.Server/Migrations/MigrationRunner.cs

@@ -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>

+ 104 - 0
Jellyfin.Server/Migrations/Routines/FixAudioData.cs

@@ -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;
+            }
+        }
+    }
+}

+ 3 - 0
MediaBrowser.Controller/Entities/InternalItemsQuery.cs

@@ -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;