mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-05-23 17:52:29 -04:00
Cleanup file related code (#14023)
This commit is contained in:
parent
4096c973c6
commit
0c3ba30de2
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
20
src/Jellyfin.Extensions/FileHelper.cs
Normal file
20
src/Jellyfin.Extensions/FileHelper.cs
Normal 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))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
23
tests/Jellyfin.Extensions.Tests/FileHelperTests.cs
Normal file
23
tests/Jellyfin.Extensions.Tests/FileHelperTests.cs
Normal 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);
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user