Cleanup file related code (#14023)

This commit is contained in:
Bond-009 2025-05-04 16:40:34 +02:00 committed by GitHub
parent 4096c973c6
commit 0c3ba30de2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 104 additions and 56 deletions

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration;
namespace Emby.Server.Implementations.AppBase
@ -91,10 +92,7 @@ namespace Emby.Server.Implementations.AppBase
/// <inheritdoc />
public void CreateAndCheckMarker(string path, string markerName, bool recursive = false)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
Directory.CreateDirectory(path);
CheckOrCreateMarker(path, $".jellyfin-{markerName}", recursive);
}
@ -115,7 +113,7 @@ namespace Emby.Server.Implementations.AppBase
var markerPath = Path.Combine(path, markerName);
if (!File.Exists(markerPath))
{
File.Create(markerPath).Dispose();
FileHelper.CreateEmpty(markerPath);
}
}
}

View File

@ -159,13 +159,13 @@ namespace Emby.Server.Implementations.IO
catch (IOException)
{
// Cross device move requires a copy
Directory.CreateDirectory(destination);
foreach (string file in Directory.GetFiles(source))
var directory = Directory.CreateDirectory(destination);
foreach (var file in directory.EnumerateFiles())
{
File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), true);
file.CopyTo(Path.Combine(destination, file.Name), true);
}
Directory.Delete(source, true);
directory.Delete(true);
}
}

View File

@ -20,7 +20,7 @@ public class DotIgnoreIgnoreRule : IResolverIgnoreRule
}
var parentDir = directory.Parent;
if (parentDir == null || parentDir.FullName == directory.FullName)
if (parentDir is null)
{
return null;
}

View File

@ -2945,7 +2945,7 @@ namespace Emby.Server.Implementations.Library
{
var path = Path.Combine(virtualFolderPath, collectionType.ToString()!.ToLowerInvariant() + ".collection"); // Can't be null with legal values?
await File.WriteAllBytesAsync(path, []).ConfigureAwait(false);
FileHelper.CreateEmpty(path);
}
CollectionFolder.SaveLibraryOptions(virtualFolderPath, options);

View File

@ -681,17 +681,17 @@ namespace Emby.Server.Implementations.Library
mediaInfo = await _mediaEncoder.GetMediaInfo(
new MediaInfoRequest
{
MediaSource = mediaSource,
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
ExtractChapters = false
},
{
MediaSource = mediaSource,
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
ExtractChapters = false
},
cancellationToken).ConfigureAwait(false);
if (cacheFilePath is not null)
{
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
FileStream createStream = File.Create(cacheFilePath);
FileStream createStream = AsyncFile.Create(cacheFilePath);
await using (createStream.ConfigureAwait(false))
{
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);

View File

@ -520,7 +520,7 @@ namespace Emby.Server.Implementations.Localization
public bool TryGetISO6392TFromB(string isoB, [NotNullWhen(true)] out string? isoT)
{
// Unlikely case the dictionary is not (yet) initialized properly
if (_iso6392BtoT == null)
if (_iso6392BtoT is null)
{
isoT = null;
return false;

View File

@ -125,7 +125,7 @@ public class SyncPlayController : BaseJellyfinApiController
{
var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(false);
var group = _syncPlayManager.GetGroup(currentSession, id);
return group == null ? NotFound() : Ok(group);
return group is null ? NotFound() : Ok(group);
}
/// <summary>

View File

@ -72,10 +72,7 @@ public static class StorageHelper
private static void TestDataDirectorySize(string path, ILogger logger, long threshold = -1)
{
logger.LogDebug("Check path {TestPath} for storage capacity", path);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
Directory.CreateDirectory(path);
var drive = new DriveInfo(path);
if (threshold != -1 && drive.AvailableFreeSpace < threshold)

View File

@ -97,28 +97,28 @@ public class TrickplayManager : ITrickplayManager
var existingResolution = resolution.Key;
var tileWidth = resolution.Value.TileWidth;
var tileHeight = resolution.Value.TileHeight;
var shouldBeSavedWithMedia = libraryOptions is null ? false : libraryOptions.SaveTrickplayWithMedia;
var localOutputDir = GetTrickplayDirectory(video, tileWidth, tileHeight, existingResolution, false);
var mediaOutputDir = GetTrickplayDirectory(video, tileWidth, tileHeight, existingResolution, true);
if (shouldBeSavedWithMedia && Directory.Exists(localOutputDir))
var shouldBeSavedWithMedia = libraryOptions is not null && libraryOptions.SaveTrickplayWithMedia;
var localOutputDir = new DirectoryInfo(GetTrickplayDirectory(video, tileWidth, tileHeight, existingResolution, false));
var mediaOutputDir = new DirectoryInfo(GetTrickplayDirectory(video, tileWidth, tileHeight, existingResolution, true));
if (shouldBeSavedWithMedia && localOutputDir.Exists)
{
var localDirFiles = Directory.GetFiles(localOutputDir);
var mediaDirExists = Directory.Exists(mediaOutputDir);
if (localDirFiles.Length > 0 && ((mediaDirExists && Directory.GetFiles(mediaOutputDir).Length == 0) || !mediaDirExists))
var localDirFiles = localOutputDir.EnumerateFiles();
var mediaDirExists = mediaOutputDir.Exists;
if (localDirFiles.Any() && ((mediaDirExists && mediaOutputDir.EnumerateFiles().Any()) || !mediaDirExists))
{
// Move images from local dir to media dir
MoveContent(localOutputDir, mediaOutputDir);
MoveContent(localOutputDir.FullName, mediaOutputDir.FullName);
_logger.LogInformation("Moved trickplay images for {ItemName} to {Location}", video.Name, mediaOutputDir);
}
}
else if (!shouldBeSavedWithMedia && Directory.Exists(mediaOutputDir))
else if (!shouldBeSavedWithMedia && mediaOutputDir.Exists)
{
var mediaDirFiles = Directory.GetFiles(mediaOutputDir);
var localDirExists = Directory.Exists(localOutputDir);
if (mediaDirFiles.Length > 0 && ((localDirExists && Directory.GetFiles(localOutputDir).Length == 0) || !localDirExists))
var mediaDirFiles = mediaOutputDir.EnumerateFiles();
var localDirExists = localOutputDir.Exists;
if (mediaDirFiles.Any() && ((localDirExists && localOutputDir.EnumerateFiles().Any()) || !localDirExists))
{
// Move images from media dir to local dir
MoveContent(mediaOutputDir, localOutputDir);
MoveContent(mediaOutputDir.FullName, localOutputDir.FullName);
_logger.LogInformation("Moved trickplay images for {ItemName} to {Location}", video.Name, localOutputDir);
}
}
@ -131,10 +131,10 @@ public class TrickplayManager : ITrickplayManager
var parent = Directory.GetParent(sourceFolder);
if (parent is not null)
{
var parentContent = Directory.GetDirectories(parent.FullName);
if (parentContent.Length == 0)
var parentContent = parent.EnumerateDirectories();
if (!parentContent.Any())
{
Directory.Delete(parent.FullName);
parent.Delete();
}
}
}
@ -220,13 +220,13 @@ public class TrickplayManager : ITrickplayManager
var tileWidth = options.TileWidth;
var tileHeight = options.TileHeight;
var saveWithMedia = libraryOptions is null ? false : libraryOptions.SaveTrickplayWithMedia;
var outputDir = GetTrickplayDirectory(video, tileWidth, tileHeight, actualWidth, saveWithMedia);
var saveWithMedia = libraryOptions is not null && libraryOptions.SaveTrickplayWithMedia;
var outputDir = new DirectoryInfo(GetTrickplayDirectory(video, tileWidth, tileHeight, actualWidth, saveWithMedia));
// Import existing trickplay tiles
if (!replace && Directory.Exists(outputDir))
if (!replace && outputDir.Exists)
{
var existingFiles = Directory.GetFiles(outputDir);
var existingFiles = outputDir.GetFiles();
if (existingFiles.Length > 0)
{
var hasTrickplayResolution = await HasTrickplayResolutionAsync(video.Id, actualWidth).ConfigureAwait(false);
@ -251,9 +251,9 @@ public class TrickplayManager : ITrickplayManager
foreach (var tile in existingFiles)
{
var image = _imageEncoder.GetImageSize(tile);
var image = _imageEncoder.GetImageSize(tile.FullName);
localTrickplayInfo.Height = Math.Max(localTrickplayInfo.Height, (int)Math.Ceiling((double)image.Height / localTrickplayInfo.TileHeight));
var bitrate = (int)Math.Ceiling((decimal)new FileInfo(tile).Length * 8 / localTrickplayInfo.TileWidth / localTrickplayInfo.TileHeight / (localTrickplayInfo.Interval / 1000));
var bitrate = (int)Math.Ceiling((decimal)tile.Length * 8 / localTrickplayInfo.TileWidth / localTrickplayInfo.TileHeight / (localTrickplayInfo.Interval / 1000));
localTrickplayInfo.Bandwidth = Math.Max(localTrickplayInfo.Bandwidth, bitrate);
}
@ -296,7 +296,7 @@ public class TrickplayManager : ITrickplayManager
.ToList();
// Create tiles
var trickplayInfo = CreateTiles(images, actualWidth, options, outputDir);
var trickplayInfo = CreateTiles(images, actualWidth, options, outputDir.FullName);
// Save tiles info
try
@ -319,7 +319,7 @@ public class TrickplayManager : ITrickplayManager
// Make sure no files stay in metadata folders on failure
// if tiles info wasn't saved.
Directory.Delete(outputDir, true);
outputDir.Delete(true);
}
}
catch (Exception ex)

View File

@ -215,7 +215,7 @@ namespace Jellyfin.Server.Extensions
});
// Add all xml doc files to swagger generator.
var xmlFiles = Directory.GetFiles(
var xmlFiles = Directory.EnumerateFiles(
AppContext.BaseDirectory,
"*.xml",
SearchOption.TopDirectoryOnly);

View File

@ -133,9 +133,9 @@ namespace MediaBrowser.MediaEncoding.Attachments
var outputFolder = _pathManager.GetAttachmentFolderPath(mediaSource.Id);
using (await _semaphoreLocks.LockAsync(outputFolder, cancellationToken).ConfigureAwait(false))
{
Directory.CreateDirectory(outputFolder);
var fileNames = Directory.GetFiles(outputFolder, "*", SearchOption.TopDirectoryOnly).Select(f => Path.GetFileName(f));
var missingFiles = mediaSource.MediaAttachments.Where(a => !fileNames.Contains(a.FileName) && !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase));
var directory = Directory.CreateDirectory(outputFolder);
var fileNames = directory.GetFiles("*", SearchOption.TopDirectoryOnly).Select(f => f.Name).ToHashSet();
var missingFiles = mediaSource.MediaAttachments.Where(a => a.FileName is not null && !fileNames.Contains(a.FileName) && !string.Equals(a.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase));
if (!missingFiles.Any())
{
// Skip extraction if all files already exist

View File

@ -26,6 +26,14 @@ namespace MediaBrowser.Model.IO
Options = FileOptions.Asynchronous
};
/// <summary>
/// Creates, or truncates and overwrites, a file in the specified path.
/// </summary>
/// <param name="path">The path and name of the file to create.</param>
/// <returns>A <see cref="FileStream" /> that provides read/write access to the file specified in path.</returns>
public static FileStream Create(string path)
=> new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
/// <summary>
/// Opens an existing file for reading.
/// </summary>

View File

@ -0,0 +1,20 @@
using System.IO;
namespace Jellyfin.Extensions;
/// <summary>
/// Provides helper functions for <see cref="File" />.
/// </summary>
public static class FileHelper
{
/// <summary>
/// Creates, or truncates a file in the specified path.
/// </summary>
/// <param name="path">The path and name of the file to create.</param>
public static void CreateEmpty(string path)
{
using (File.OpenHandle(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
{
}
}
}

View File

@ -363,7 +363,7 @@ namespace Jellyfin.LiveTv.Channels
Directory.CreateDirectory(Path.GetDirectoryName(path));
FileStream createStream = File.Create(path);
FileStream createStream = AsyncFile.Create(path);
await using (createStream.ConfigureAwait(false))
{
await JsonSerializer.SerializeAsync(createStream, mediaSources, _jsonOptions).ConfigureAwait(false);
@ -866,7 +866,7 @@ namespace Jellyfin.LiveTv.Channels
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
var createStream = File.Create(path);
var createStream = AsyncFile.Create(path);
await using (createStream.ConfigureAwait(false))
{
await JsonSerializer.SerializeAsync(createStream, result, _jsonOptions).ConfigureAwait(false);

View File

@ -0,0 +1,23 @@
using System.IO;
using Xunit;
namespace Jellyfin.Extensions.Tests;
public static class FileHelperTests
{
[Fact]
public static void CreateEmpty_Valid_Correct()
{
var path = Path.Join(Path.GetTempPath(), Path.GetRandomFileName());
var fileInfo = new FileInfo(path);
Assert.False(fileInfo.Exists);
FileHelper.CreateEmpty(path);
fileInfo.Refresh();
Assert.True(fileInfo.Exists);
File.Delete(path);
}
}

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using AutoFixture;
using Emby.Server.Implementations.Library;
using Emby.Server.Implementations.Plugins;
using Jellyfin.Extensions;
using Jellyfin.Extensions.Json;
using Jellyfin.Extensions.Json.Converters;
using MediaBrowser.Common.Plugins;
@ -85,7 +86,7 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
var dllPath = Path.GetDirectoryName(Path.Combine(_pluginPath, dllFile))!;
Directory.CreateDirectory(dllPath);
File.Create(Path.Combine(dllPath, filename));
FileHelper.CreateEmpty(Path.Combine(dllPath, filename));
var metafilePath = Path.Combine(_pluginPath, "meta.json");
File.WriteAllText(metafilePath, JsonSerializer.Serialize(manifest, _options));
@ -141,7 +142,7 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
foreach (var file in files)
{
File.Create(Path.Combine(_pluginPath, file));
FileHelper.CreateEmpty(Path.Combine(_pluginPath, file));
}
var metafilePath = Path.Combine(_pluginPath, "meta.json");

View File

@ -1,6 +1,7 @@
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using Xunit;
using Xunit.Abstractions;
@ -33,7 +34,7 @@ namespace Jellyfin.Server.Integration.Tests
// Write out for publishing
string outputPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "openapi.json"));
_outputHelper.WriteLine("Writing OpenAPI Spec JSON to '{0}'.", outputPath);
await using var fs = File.Create(outputPath);
await using var fs = AsyncFile.Create(outputPath);
await response.Content.CopyToAsync(fs);
}
}