diff options
Diffstat (limited to 'Jellyfin.Server/Migrations')
6 files changed, 127 insertions, 24 deletions
diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index 44aa43044..81fecc9a1 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/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> diff --git a/Jellyfin.Server/Migrations/Routines/AddDefaultCastReceivers.cs b/Jellyfin.Server/Migrations/Routines/AddDefaultCastReceivers.cs index 75a6a6176..57a5c8a62 100644 --- a/Jellyfin.Server/Migrations/Routines/AddDefaultCastReceivers.cs +++ b/Jellyfin.Server/Migrations/Routines/AddDefaultCastReceivers.cs @@ -32,24 +32,20 @@ public class AddDefaultCastReceivers : IMigrationRoutine /// <inheritdoc /> public void Perform() { - // Only add if receiver list is empty. - if (_serverConfigurationManager.Configuration.CastReceiverApplications.Length == 0) - { - _serverConfigurationManager.Configuration.CastReceiverApplications = new CastReceiverApplication[] + _serverConfigurationManager.Configuration.CastReceiverApplications = + [ + new() { - new() - { - Id = "F007D354", - Name = "Stable" - }, - new() - { - Id = "6F511C87", - Name = "Unstable" - } - }; - - _serverConfigurationManager.SaveConfiguration(); - } + Id = "F007D354", + Name = "Stable" + }, + new() + { + Id = "6F511C87", + Name = "Unstable" + } + ]; + + _serverConfigurationManager.SaveConfiguration(); } } diff --git a/Jellyfin.Server/Migrations/Routines/FixAudioData.cs b/Jellyfin.Server/Migrations/Routines/FixAudioData.cs new file mode 100644 index 000000000..a20253369 --- /dev/null +++ b/Jellyfin.Server/Migrations/Routines/FixAudioData.cs @@ -0,0 +1,106 @@ +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 + { + _logger.LogInformation("Backing up {Library} to {BackupPath}", DbFilename, bakPath); + File.Copy(dbPath, bakPath); + _logger.LogInformation("{Library} backed up to {BackupPath}", DbFilename, 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 = 5000, + 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 += results.Count; + _logger.LogInformation("Backfilled data for {UpdatedRecords} of {TotalRecords} audio records", startIndex, records); + } + } + } +} diff --git a/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs b/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs index cf3182003..3655a610d 100644 --- a/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs +++ b/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs @@ -54,12 +54,12 @@ internal class FixPlaylistOwner : IMigrationRoutine foreach (var playlist in playlists) { var shares = playlist.Shares; - if (shares.Length > 0) + if (shares.Count > 0) { var firstEditShare = shares.First(x => x.CanEdit); - if (firstEditShare is not null && Guid.TryParse(firstEditShare.UserId, out var guid)) + if (firstEditShare is not null) { - playlist.OwnerUserId = guid; + playlist.OwnerUserId = firstEditShare.UserId; playlist.Shares = shares.Where(x => x != firstEditShare).ToArray(); playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).GetAwaiter().GetResult(); _playlistManager.SavePlaylistFile(playlist); diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index 4fee88b68..808c5e33b 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -67,7 +67,7 @@ namespace Jellyfin.Server.Migrations.Routines using (var connection = new SqliteConnection($"Filename={Path.Combine(dataPath, DbFilename)}")) { connection.Open(); - var dbContext = _provider.CreateDbContext(); + using var dbContext = _provider.CreateDbContext(); var queryResult = connection.Query("SELECT * FROM LocalUsersv2"); diff --git a/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs b/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs index 9137ea234..52fb93d59 100644 --- a/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs +++ b/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs @@ -42,7 +42,7 @@ namespace Jellyfin.Server.Migrations.Routines } var libraryOptions = virtualFolder.LibraryOptions; - var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(folderId); + var collectionFolder = _libraryManager.GetItemById<CollectionFolder>(folderId) ?? throw new InvalidOperationException("Failed to find CollectionFolder"); // The property no longer exists in LibraryOptions, so we just re-save the options to get old data removed. collectionFolder.UpdateLibraryOptions(libraryOptions); _logger.LogInformation("Removed from '{VirtualFolder}'", virtualFolder.Name); |
