diff options
| author | Bond-009 <bond.009@outlook.com> | 2026-04-24 19:00:19 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-24 19:00:19 +0200 |
| commit | a183fce142a47db3b2b9faa1e0f2863f0d56e5a1 (patch) | |
| tree | 8637cf347d573917242a3c5546baee33028825a3 /Jellyfin.Server.Implementations/FullSystemBackup/BackupService.cs | |
| parent | d1f242bc097b1530de27d5e74f303ff06096c294 (diff) | |
| parent | b1e2419c6593a3aa4c8df3778831a3214ae5a1c0 (diff) | |
Merge branch 'master' into Preservation-of-Watched-Status-on-Re-watch
Diffstat (limited to 'Jellyfin.Server.Implementations/FullSystemBackup/BackupService.cs')
| -rw-r--r-- | Jellyfin.Server.Implementations/FullSystemBackup/BackupService.cs | 36 |
1 files changed, 27 insertions, 9 deletions
diff --git a/Jellyfin.Server.Implementations/FullSystemBackup/BackupService.cs b/Jellyfin.Server.Implementations/FullSystemBackup/BackupService.cs index 70483c36cc..a6dc5458ee 100644 --- a/Jellyfin.Server.Implementations/FullSystemBackup/BackupService.cs +++ b/Jellyfin.Server.Implementations/FullSystemBackup/BackupService.cs @@ -102,7 +102,7 @@ public class BackupService : IBackupService } BackupManifest? manifest; - var manifestStream = zipArchiveEntry.Open(); + var manifestStream = await zipArchiveEntry.OpenAsync().ConfigureAwait(false); await using (manifestStream.ConfigureAwait(false)) { manifest = await JsonSerializer.DeserializeAsync<BackupManifest>(manifestStream, _serializerSettings).ConfigureAwait(false); @@ -118,15 +118,21 @@ public class BackupService : IBackupService throw new NotSupportedException($"The loaded archive '{archivePath}' is made for a newer version of Jellyfin ({manifest.ServerVersion}) and cannot be loaded in this version."); } - void CopyDirectory(string source, string target) + void CopyDirectory(string source, string target, string[]? exclude = null) { var fullSourcePath = NormalizePathSeparator(Path.GetFullPath(source) + Path.DirectorySeparatorChar); var fullTargetRoot = Path.GetFullPath(target) + Path.DirectorySeparatorChar; + var excludePaths = exclude?.Select(e => $"{source}/{e}/").ToArray(); foreach (var item in zipArchive.Entries) { var sourcePath = NormalizePathSeparator(Path.GetFullPath(item.FullName)); var targetPath = Path.GetFullPath(Path.Combine(target, Path.GetRelativePath(source, item.FullName))); + if (excludePaths is not null && excludePaths.Any(e => item.FullName.StartsWith(e, StringComparison.Ordinal))) + { + continue; + } + if (!sourcePath.StartsWith(fullSourcePath, StringComparison.Ordinal) || !targetPath.StartsWith(fullTargetRoot, StringComparison.Ordinal) || Path.EndsInDirectorySeparator(item.FullName)) @@ -142,8 +148,10 @@ public class BackupService : IBackupService } CopyDirectory("Config", _applicationPaths.ConfigurationDirectoryPath); - CopyDirectory("Data", _applicationPaths.DataPath); + CopyDirectory("Data", _applicationPaths.DataPath, exclude: ["metadata", "metadata-default"]); CopyDirectory("Root", _applicationPaths.RootFolderPath); + CopyDirectory("Data/metadata", _applicationPaths.InternalMetadataPath); + CopyDirectory("Data/metadata-default", _applicationPaths.DefaultInternalMetadataPath); if (manifest.Options.Database) { @@ -160,7 +168,7 @@ public class BackupService : IBackupService } HistoryRow[] historyEntries; - var historyArchive = historyEntry.Open(); + var historyArchive = await historyEntry.OpenAsync().ConfigureAwait(false); await using (historyArchive.ConfigureAwait(false)) { historyEntries = await JsonSerializer.DeserializeAsync<HistoryRow[]>(historyArchive).ConfigureAwait(false) ?? @@ -204,7 +212,7 @@ public class BackupService : IBackupService continue; } - var zipEntryStream = zipEntry.Open(); + var zipEntryStream = await zipEntry.OpenAsync().ConfigureAwait(false); await using (zipEntryStream.ConfigureAwait(false)) { _logger.LogInformation("Restore backup of {Table}", entityType.Type.Name); @@ -329,7 +337,7 @@ public class BackupService : IBackupService _logger.LogInformation("Begin backup of entity {Table}", entityType.SourceName); var zipEntry = zipArchive.CreateEntry(NormalizePathSeparator(Path.Combine("Database", $"{entityType.SourceName}.json"))); var entities = 0; - var zipEntryStream = zipEntry.Open(); + var zipEntryStream = await zipEntry.OpenAsync().ConfigureAwait(false); await using (zipEntryStream.ConfigureAwait(false)) { var jsonSerializer = new Utf8JsonWriter(zipEntryStream); @@ -366,7 +374,7 @@ public class BackupService : IBackupService foreach (var item in Directory.EnumerateFiles(_applicationPaths.ConfigurationDirectoryPath, "*.xml", SearchOption.TopDirectoryOnly) .Union(Directory.EnumerateFiles(_applicationPaths.ConfigurationDirectoryPath, "*.json", SearchOption.TopDirectoryOnly))) { - zipArchive.CreateEntryFromFile(item, NormalizePathSeparator(Path.Combine("Config", Path.GetFileName(item)))); + await zipArchive.CreateEntryFromFileAsync(item, NormalizePathSeparator(Path.Combine("Config", Path.GetFileName(item)))).ConfigureAwait(false); } void CopyDirectory(string source, string target, string filter = "*") @@ -380,6 +388,7 @@ public class BackupService : IBackupService foreach (var item in Directory.EnumerateFiles(source, filter, SearchOption.AllDirectories)) { + // TODO: @bond make async zipArchive.CreateEntryFromFile(item, NormalizePathSeparator(Path.Combine(target, Path.GetRelativePath(source, item)))); } } @@ -403,9 +412,18 @@ public class BackupService : IBackupService if (backupOptions.Metadata) { CopyDirectory(Path.Combine(_applicationPaths.InternalMetadataPath), Path.Combine("Data", "metadata")); + + // If a custom metadata path is configured, the default location may still contain data. + if (!string.Equals( + Path.GetFullPath(_applicationPaths.DefaultInternalMetadataPath), + Path.GetFullPath(_applicationPaths.InternalMetadataPath), + StringComparison.OrdinalIgnoreCase)) + { + CopyDirectory(Path.Combine(_applicationPaths.DefaultInternalMetadataPath), Path.Combine("Data", "metadata-default")); + } } - var manifestStream = zipArchive.CreateEntry(ManifestEntryName).Open(); + var manifestStream = await zipArchive.CreateEntry(ManifestEntryName).OpenAsync().ConfigureAwait(false); await using (manifestStream.ConfigureAwait(false)) { await JsonSerializer.SerializeAsync(manifestStream, manifest).ConfigureAwait(false); @@ -505,7 +523,7 @@ public class BackupService : IBackupService return null; } - var manifestStream = manifestEntry.Open(); + var manifestStream = await manifestEntry.OpenAsync().ConfigureAwait(false); await using (manifestStream.ConfigureAwait(false)) { return await JsonSerializer.DeserializeAsync<BackupManifest>(manifestStream, _serializerSettings).ConfigureAwait(false); |
