diff --git a/.editorconfig b/.editorconfig
index 0e17ec0e..a0e1a0fb 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,13 +1,38 @@
-# EditorConfig for MediaBrowser.Model# https://EditorConfig.orgroot = true[*]charset = utf-8insert_final_newline = truetrim_trailing_whitespace = true[*.cs]indent_size = 4indent_style = spacedotnet_sort_system_directives_first = truedotnet_separate_import_directive_groups = false# StyleCop Analyzer Rules - Disabled for project consistencydotnet_diagnostic.SA1101.severity = nonedotnet_diagnostic.SA1309.severity = nonedotnet_diagnostic.SA1204.severity = nonedotnet_diagnostic.SA1202.severity = nonedotnet_diagnostic.SA1135.severity = nonedotnet_diagnostic.SA1600.severity = suggestion# StyleCop Analyzer Rules - Keep enableddotnet_diagnostic.SA1413.severity = warningdotnet_diagnostic.SA1515.severity = warningdotnet_diagnostic.SA1518.severity = warning-
+# EditorConfig for MediaBrowser.Model
+# https://EditorConfig.org
+root = true
-# StyleCop Analyzer Rules - Additional suppressions for Emby.Naming
-dotnet_diagnostic.SA1200.severity = none
-dotnet_diagnostic.SA1633.severity = none
+[*]
+charset = utf-8
+insert_final_newline = true
+trim_trailing_whitespace = true
-# Reduce severity for trailing commas and comments
+[*.cs]
+indent_size = 4
+indent_style = space
+dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = false
+
+# StyleCop Analyzer Rules - Disabled for project consistency
+dotnet_diagnostic.SA1101.severity = none
+dotnet_diagnostic.SA1309.severity = none
+dotnet_diagnostic.SA1204.severity = none
+dotnet_diagnostic.SA1202.severity = none
+dotnet_diagnostic.SA1135.severity = none
+dotnet_diagnostic.SA1600.severity = none
+dotnet_diagnostic.SA1601.severity = none
+
+# StyleCop Analyzer Rules - Reduced severity
dotnet_diagnostic.SA1413.severity = silent
dotnet_diagnostic.SA1515.severity = silent
+dotnet_diagnostic.SA1512.severity = silent
+dotnet_diagnostic.SA1518.severity = warning
+dotnet_diagnostic.SA1648.severity = none
+
+# StyleCop Analyzer Rules - Additional suppressions
+dotnet_diagnostic.SA1200.severity = none
+dotnet_diagnostic.SA1633.severity = none
# IDE Rules - Suppress non-critical suggestions
dotnet_diagnostic.IDE0008.severity = silent
@@ -17,7 +42,7 @@ dotnet_diagnostic.IDE0051.severity = warning
dotnet_diagnostic.IDE0055.severity = warning
dotnet_diagnostic.IDE0057.severity = silent
dotnet_diagnostic.IDE0058.severity = silent
-dotnet_diagnostic.IDE0065.severity = silent
+dotnet_diagnostic.IDE0065.severity = none
dotnet_diagnostic.IDE0078.severity = silent
dotnet_diagnostic.IDE0090.severity = silent
dotnet_diagnostic.IDE0160.severity = silent
@@ -33,4 +58,3 @@ dotnet_diagnostic.CA1310.severity = warning
# C# Code Style - Using directive placement
csharp_using_directive_placement = outside_namespace:silent
-
diff --git a/Directory.Build.props b/Directory.Build.props
index 8400f4c5..218fbba6 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -8,10 +8,14 @@
true
NU1902;NU1903
+
+ $(NoWarn);IDE0065
AllEnabledByDefault
+
+ false
diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj
index 85b06207..14306045 100644
--- a/Emby.Naming/Emby.Naming.csproj
+++ b/Emby.Naming/Emby.Naming.csproj
@@ -20,6 +20,7 @@
false
false
+ $(NoWarn);IDE0065
diff --git a/Emby.Photos/PhotoProvider.cs b/Emby.Photos/PhotoProvider.cs
index 0099fb90..ee36e6be 100644
--- a/Emby.Photos/PhotoProvider.cs
+++ b/Emby.Photos/PhotoProvider.cs
@@ -2,178 +2,165 @@
// Copyright (c) PlaceholderCompany. All rights reserved.
//
-namespace Emby.Photos;
+#pragma warning disable SA1309 // Variables should not begin with underscore
-using System;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Jellyfin.Extensions;
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-using Microsoft.Extensions.Logging;
-using TagLib;
-using TagLib.IFD;
-using TagLib.IFD.Entries;
-using TagLib.IFD.Tags;
-
-///
-/// Metadata provider for photos.
-///
-public class PhotoProvider : ICustomMetadataProvider, IForcedProvider, IHasItemChangeMonitor
+namespace Emby.Photos
{
- private readonly ILogger _logger;
- private readonly IImageProcessor _imageProcessor;
-
- // Other extensions might cause taglib to hang
- private readonly string[] _includeExtensions = [".jpg", ".jpeg", ".png", ".tiff", ".cr2", ".webp", ".avif"];
+ using System;
+ using System.IO;
+ using System.Linq;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Jellyfin.Extensions;
+ using MediaBrowser.Controller.Drawing;
+ using MediaBrowser.Controller.Entities;
+ using MediaBrowser.Controller.Library;
+ using MediaBrowser.Controller.Providers;
+ using MediaBrowser.Model.Drawing;
+ using MediaBrowser.Model.Entities;
+ using MediaBrowser.Model.IO;
+ using Microsoft.Extensions.Logging;
+ using TagLib;
+ using TagLib.IFD;
+ using TagLib.IFD.Entries;
+ using TagLib.IFD.Tags;
///
- /// Initializes a new instance of the class.
+ /// Metadata provider for photos.
///
/// The logger.
/// The image processor.
- public PhotoProvider(ILogger logger, IImageProcessor imageProcessor)
+ public class PhotoProvider(ILogger logger, IImageProcessor imageProcessor) : ICustomMetadataProvider, IForcedProvider, IHasItemChangeMonitor
{
- _logger = logger;
- _imageProcessor = imageProcessor;
- }
+ // Other extensions might cause taglib to hang
+ private readonly string[] _includeExtensions = [".jpg", ".jpeg", ".png", ".tiff", ".cr2", ".webp", ".avif"];
- ///
- public string Name => "Embedded Information";
+ ///
+ public string Name => "Embedded Information";
- ///
- public bool HasChanged(BaseItem item, IDirectoryService directoryService)
- {
- if (item.IsFileProtocol)
+ ///
+ public bool HasChanged(BaseItem item, IDirectoryService directoryService)
{
- var file = directoryService.GetFile(item.Path);
- return file is not null && item.HasChanged(file.LastWriteTimeUtc);
+ if (item.IsFileProtocol)
+ {
+ FileSystemMetadata? file = directoryService.GetFile(item.Path);
+ return file is not null && item.HasChanged(file.LastWriteTimeUtc);
+ }
+
+ return false;
}
- return false;
- }
-
- ///
- public Task FetchAsync(Photo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
- {
- item.SetImagePath(ImageType.Primary, item.Path);
-
- // Examples: https://github.com/mono/taglib-sharp/blob/a5f6949a53d09ce63ee7495580d6802921a21f14/tests/fixtures/TagLib.Tests.Images/NullOrientationTest.cs
- if (_includeExtensions.Contains(Path.GetExtension(item.Path.AsSpan()), StringComparison.OrdinalIgnoreCase))
+ ///
+ public Task FetchAsync(Photo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
{
- try
- {
- using var file = TagLib.File.Create(item.Path);
- if (file.GetTag(TagTypes.TiffIFD) is IFDTag tag)
- {
- var structure = tag.Structure;
- if (structure?.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) is SubIFDEntry exif)
- {
- var exifStructure = exif.Structure;
- if (exifStructure is not null)
- {
- if (exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) is RationalIFDEntry apertureEntry)
- {
- item.Aperture = (double)apertureEntry.Value.Numerator / apertureEntry.Value.Denominator;
- }
+ item.SetImagePath(ImageType.Primary, item.Path);
- if (exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) is RationalIFDEntry shutterSpeedEntry)
+ // Examples: https://github.com/mono/taglib-sharp/blob/a5f6949a53d09ce63ee7495580d6802921a21f14/tests/fixtures/TagLib.Tests.Images/NullOrientationTest.cs
+ if (this._includeExtensions.Contains(Path.GetExtension(item.Path.AsSpan()), StringComparison.OrdinalIgnoreCase))
+ {
+ try
+ {
+ using TagLib.File file = TagLib.File.Create(item.Path);
+ if (file.GetTag(TagTypes.TiffIFD) is IFDTag tag)
+ {
+ IFDStructure? structure = tag.Structure;
+ if (structure?.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) is SubIFDEntry exif)
+ {
+ IFDStructure? exifStructure = exif.Structure;
+ if (exifStructure is not null)
{
- item.ShutterSpeed = (double)shutterSpeedEntry.Value.Numerator / shutterSpeedEntry.Value.Denominator;
+ if (exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) is RationalIFDEntry apertureEntry)
+ {
+ item.Aperture = (double)apertureEntry.Value.Numerator / apertureEntry.Value.Denominator;
+ }
+
+ if (exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) is RationalIFDEntry shutterSpeedEntry)
+ {
+ item.ShutterSpeed = (double)shutterSpeedEntry.Value.Numerator / shutterSpeedEntry.Value.Denominator;
+ }
}
}
}
- }
- if (file is TagLib.Image.File image)
+ if (file is TagLib.Image.File image)
+ {
+ item.CameraMake = image.ImageTag.Make;
+ item.CameraModel = image.ImageTag.Model;
+
+ item.Width = image.Properties.PhotoWidth;
+ item.Height = image.Properties.PhotoHeight;
+
+ item.CommunityRating = image.ImageTag.Rating;
+
+ item.Overview = image.ImageTag.Comment;
+
+ if (!string.IsNullOrWhiteSpace(image.ImageTag.Title)
+ && !item.LockedFields.Contains(MetadataField.Name))
+ {
+ item.Name = image.ImageTag.Title;
+ }
+
+ DateTime? dateTaken = image.ImageTag.DateTime;
+ if (dateTaken.HasValue)
+ {
+ item.DateCreated = dateTaken.Value.ToUniversalTime();
+ item.PremiereDate = dateTaken.Value;
+ item.ProductionYear = dateTaken.Value.Year;
+ }
+
+ item.Genres = image.ImageTag.Genres;
+ item.Tags = image.ImageTag.Keywords;
+ item.Software = image.ImageTag.Software;
+
+ if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
+ {
+ item.Orientation = null;
+ }
+ else if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out ImageOrientation orientation))
+ {
+ item.Orientation = orientation;
+ }
+
+ item.ExposureTime = image.ImageTag.ExposureTime;
+ item.FocalLength = image.ImageTag.FocalLength;
+
+ item.Latitude = image.ImageTag.Latitude;
+ item.Longitude = image.ImageTag.Longitude;
+ item.Altitude = image.ImageTag.Altitude;
+
+ item.IsoSpeedRating = image.ImageTag.ISOSpeedRatings.HasValue
+ ? Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value)
+ : null;
+ }
+ }
+ catch (Exception ex)
{
- item.CameraMake = image.ImageTag.Make;
- item.CameraModel = image.ImageTag.Model;
-
- item.Width = image.Properties.PhotoWidth;
- item.Height = image.Properties.PhotoHeight;
-
- item.CommunityRating = image.ImageTag.Rating;
-
- item.Overview = image.ImageTag.Comment;
-
- if (!string.IsNullOrWhiteSpace(image.ImageTag.Title)
- && !item.LockedFields.Contains(MetadataField.Name))
- {
- item.Name = image.ImageTag.Title;
- }
-
- var dateTaken = image.ImageTag.DateTime;
- if (dateTaken.HasValue)
- {
- item.DateCreated = dateTaken.Value.ToUniversalTime();
- item.PremiereDate = dateTaken.Value;
- item.ProductionYear = dateTaken.Value.Year;
- }
-
- item.Genres = image.ImageTag.Genres;
- item.Tags = image.ImageTag.Keywords;
- item.Software = image.ImageTag.Software;
-
- if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
- {
- item.Orientation = null;
- }
- else if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out ImageOrientation orientation))
- {
- item.Orientation = orientation;
- }
-
- item.ExposureTime = image.ImageTag.ExposureTime;
- item.FocalLength = image.ImageTag.FocalLength;
-
- item.Latitude = image.ImageTag.Latitude;
- item.Longitude = image.ImageTag.Longitude;
- item.Altitude = image.ImageTag.Altitude;
-
- if (image.ImageTag.ISOSpeedRatings.HasValue)
- {
- item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value);
- }
- else
- {
- item.IsoSpeedRating = null;
- }
+ logger.LogError(ex, "Image Provider - Error reading image tag for {0}", item.Path);
}
}
- catch (Exception ex)
+
+ if (item.Width <= 0 || item.Height <= 0)
{
- _logger.LogError(ex, "Image Provider - Error reading image tag for {0}", item.Path);
- }
- }
+ ItemImageInfo img = item.GetImageInfo(ImageType.Primary, 0);
- if (item.Width <= 0 || item.Height <= 0)
- {
- var img = item.GetImageInfo(ImageType.Primary, 0);
-
- try
- {
- var size = _imageProcessor.GetImageDimensions(item, img);
-
- if (size.Width > 0 && size.Height > 0)
+ try
{
- item.Width = size.Width;
- item.Height = size.Height;
+ ImageDimensions size = imageProcessor.GetImageDimensions(item, img);
+
+ if (size.Width > 0 && size.Height > 0)
+ {
+ item.Width = size.Width;
+ item.Height = size.Height;
+ }
+ }
+ catch (ArgumentException)
+ {
+ // format not supported
}
}
- catch (ArgumentException)
- {
- // format not supported
- }
- }
- const ItemUpdateType Result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport;
- return Task.FromResult(Result);
+ const ItemUpdateType Result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport;
+ return Task.FromResult(Result);
+ }
}
}
diff --git a/Emby.Photos/obj/project.nuget.cache b/Emby.Photos/obj/project.nuget.cache
index db61bb8d..71b5a2a2 100644
--- a/Emby.Photos/obj/project.nuget.cache
+++ b/Emby.Photos/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "DaMoU2oavX0=",
+ "dgSpecHash": "leFWYb0Dcsk=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\Emby.Photos\\Emby.Photos.csproj",
"expectedPackageFiles": [
diff --git a/Emby.Server.Implementations/obj/project.nuget.cache b/Emby.Server.Implementations/obj/project.nuget.cache
index 769321e3..c6a9b337 100644
--- a/Emby.Server.Implementations/obj/project.nuget.cache
+++ b/Emby.Server.Implementations/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "CU3WcVn0qXE=",
+ "dgSpecHash": "ZVA5ePVHqjg=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\Emby.Server.Implementations\\Emby.Server.Implementations.csproj",
"expectedPackageFiles": [
diff --git a/HOW_TO_IGNORE_IDE0065.md b/HOW_TO_IGNORE_IDE0065.md
new file mode 100644
index 00000000..63109652
--- /dev/null
+++ b/HOW_TO_IGNORE_IDE0065.md
@@ -0,0 +1,177 @@
+# How to Ignore IDE0065 Error Message
+
+## What is IDE0065?
+
+**IDE0065**: "Using directives must be placed outside of a namespace declaration"
+
+This is a code style warning about where `using` statements should be placed - inside or outside the namespace.
+
+## Solutions Implemented ✅
+
+### Solution 1: .editorconfig (Applied) ✅
+
+Updated `.editorconfig` to completely disable IDE0065:
+
+```ini
+# IDE Rules - Suppress non-critical suggestions
+dotnet_diagnostic.IDE0065.severity = none
+```
+
+**Severity Levels:**
+- `none` = Completely disabled (doesn't appear anywhere)
+- `silent` = Hidden in IDE, but may show in build
+- `suggestion` = Shows as hint in IDE
+- `warning` = Shows as warning
+- `error` = Blocks build
+
+### Solution 2: Project File (Applied) ✅
+
+Added to `Emby.Naming.csproj`:
+
+```xml
+
+ $(NoWarn);IDE0065
+
+```
+
+This ensures IDE0065 is completely suppressed during build.
+
+## Additional Methods (If Needed)
+
+### Method 3: Global Suppression File
+
+Create a file `GlobalSuppressions.cs` in your project:
+
+```csharp
+//
+// Copyright (c) PlaceholderCompany. All rights reserved.
+//
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Style", "IDE0065:Misplaced using directive", Justification = "Project style preference")]
+```
+
+### Method 4: Suppress for All Configurations
+
+If you want to suppress IDE0065 for **both Debug and Release**, add this to your `.csproj`:
+
+```xml
+
+ $(NoWarn);IDE0065
+
+```
+
+### Method 5: Visual Studio Settings (Local Only)
+
+If you only want to hide it in **your IDE** (doesn't affect builds):
+
+1. Open Visual Studio
+2. **Tools** → **Options**
+3. **Text Editor** → **C#** → **Code Style** → **Formatting**
+4. Under "Usings", set your preference
+5. Or go to **Options** → **Environment** → **Task List** and filter warnings
+
+**Note:** This only affects your local IDE, not team builds.
+
+## Verify the Changes
+
+### Check in Visual Studio:
+1. Restart Visual Studio (or reload solution)
+2. Build the project
+3. IDE0065 should no longer appear in Error List
+
+### Check in Command Line:
+```powershell
+# Clean and rebuild
+dotnet clean Emby.Naming\Emby.Naming.csproj
+dotnet build Emby.Naming\Emby.Naming.csproj
+
+# IDE0065 should not appear in output
+```
+
+## What the Changes Mean
+
+### For Your IDE:
+- ✅ IDE0065 will **not show** in the Error List
+- ✅ No underlines or suggestions in the code editor
+- ✅ Quick Actions (Ctrl+.) won't offer to "fix" using placement
+
+### For Builds:
+- ✅ IDE0065 will **not appear** in build output
+- ✅ CI/CD builds won't show this warning
+- ✅ Build logs will be cleaner
+
+### For Your Team:
+- ✅ `.editorconfig` is checked into source control
+- ✅ All developers will have the same suppression
+- ✅ Consistent experience across the team
+
+## Why Both Methods?
+
+We applied **both** methods for maximum coverage:
+
+1. **`.editorconfig`** → Suppresses in IDE and most build scenarios
+2. **``** → Guarantees suppression during MSBuild/command-line builds
+
+This ensures IDE0065 is completely eliminated everywhere!
+
+## Other Common IDE Errors to Suppress
+
+If you want to suppress other common warnings, add them to ``:
+
+```xml
+
+ $(NoWarn);IDE0065;IDE0008;IDE0058;SA1309;SA1101
+
+```
+
+**Common Ones:**
+- `IDE0008` = Use explicit type instead of 'var'
+- `IDE0058` = Expression value is never used
+- `IDE0065` = Using directive placement
+- `SA1309` = Field names should not begin with underscore
+- `SA1101` = Prefix local calls with 'this'
+- `SA1200` = Using directives placement (StyleCop version)
+
+## Testing
+
+After making these changes:
+
+```powershell
+# 1. Clean everything
+dotnet clean
+
+# 2. Rebuild
+dotnet build Emby.Naming\Emby.Naming.csproj
+
+# 3. Check for IDE0065 in output (should be gone!)
+```
+
+Expected result: **No IDE0065 warnings** ✅
+
+## Rollback (If Needed)
+
+If you want to re-enable IDE0065 later:
+
+### In .editorconfig:
+```ini
+dotnet_diagnostic.IDE0065.severity = suggestion
+```
+
+### In .csproj:
+Remove `IDE0065` from the `` list.
+
+## Summary
+
+✅ **Both methods applied!**
+- `.editorconfig` updated: `IDE0065.severity = none`
+- `Emby.Naming.csproj` updated: `$(NoWarn);IDE0065`
+
+**Result:** IDE0065 is now completely suppressed in:
+- ✅ Visual Studio IDE
+- ✅ Command-line builds
+- ✅ MSBuild
+- ✅ CI/CD pipelines
+
+You should no longer see IDE0065 anywhere! 🎉
diff --git a/Jellyfin.Api/obj/project.nuget.cache b/Jellyfin.Api/obj/project.nuget.cache
index 3b4b499f..fccf3de6 100644
--- a/Jellyfin.Api/obj/project.nuget.cache
+++ b/Jellyfin.Api/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "sEpjYe2J48k=",
+ "dgSpecHash": "4CpeL+8YFHs=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\Jellyfin.Api\\Jellyfin.Api.csproj",
"expectedPackageFiles": [
diff --git a/Jellyfin.Server.Implementations/obj/project.nuget.cache b/Jellyfin.Server.Implementations/obj/project.nuget.cache
index db5a88c8..4131b5d7 100644
--- a/Jellyfin.Server.Implementations/obj/project.nuget.cache
+++ b/Jellyfin.Server.Implementations/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "2uqnqkg9VpI=",
+ "dgSpecHash": "8rGyZK2RqJs=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\Jellyfin.Server.Implementations\\Jellyfin.Server.Implementations.csproj",
"expectedPackageFiles": [
diff --git a/Jellyfin.Server/obj/project.nuget.cache b/Jellyfin.Server/obj/project.nuget.cache
index 19436215..09ef9e03 100644
--- a/Jellyfin.Server/obj/project.nuget.cache
+++ b/Jellyfin.Server/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "uvfyRwbCsEk=",
+ "dgSpecHash": "WNAhlXOd1t0=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\Jellyfin.Server\\Jellyfin.Server.csproj",
"expectedPackageFiles": [
diff --git a/MediaBrowser.Controller/.editorconfig b/MediaBrowser.Controller/.editorconfig
new file mode 100644
index 00000000..dc2cdf37
--- /dev/null
+++ b/MediaBrowser.Controller/.editorconfig
@@ -0,0 +1,27 @@
+# EditorConfig for MediaBrowser.Controller
+# https://EditorConfig.org
+
+root = true
+
+[*.cs]
+# Disable StyleCop rules that are not followed in this legacy project
+dotnet_diagnostic.SA1101.severity = none
+dotnet_diagnostic.SA1200.severity = none
+dotnet_diagnostic.SA1202.severity = none
+dotnet_diagnostic.SA1204.severity = none
+dotnet_diagnostic.SA1309.severity = none
+dotnet_diagnostic.SA1413.severity = none
+dotnet_diagnostic.SA1515.severity = none
+dotnet_diagnostic.SA1512.severity = none
+dotnet_diagnostic.SA1600.severity = none
+dotnet_diagnostic.SA1601.severity = none
+dotnet_diagnostic.SA1602.severity = none
+dotnet_diagnostic.SA1128.severity = none
+dotnet_diagnostic.SA1009.severity = none
+dotnet_diagnostic.SA1108.severity = none
+
+# Disable IDisposableAnalyzers rules
+dotnet_diagnostic.IDISP001.severity = none
+dotnet_diagnostic.IDISP003.severity = none
+dotnet_diagnostic.IDISP007.severity = none
+dotnet_diagnostic.IDISP008.severity = none
diff --git a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
index 72cec9bf..8b6e1b00 100644
--- a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
+++ b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
@@ -23,7 +23,7 @@ namespace MediaBrowser.Controller.BaseItemManager
/// Instance of the interface.
public BaseItemManager(IServerConfigurationManager serverConfigurationManager)
{
- _serverConfigurationManager = serverConfigurationManager;
+ this._serverConfigurationManager = serverConfigurationManager;
}
///
@@ -46,7 +46,7 @@ namespace MediaBrowser.Controller.BaseItemManager
return libraryTypeOptions.MetadataFetchers.Contains(name, StringComparison.OrdinalIgnoreCase);
}
- var itemConfig = _serverConfigurationManager.GetMetadataOptionsForType(baseItem.GetType().Name);
+ var itemConfig = this._serverConfigurationManager.GetMetadataOptionsForType(baseItem.GetType().Name);
return itemConfig is null || !itemConfig.DisabledMetadataFetchers.Contains(name, StringComparison.OrdinalIgnoreCase);
}
@@ -70,7 +70,7 @@ namespace MediaBrowser.Controller.BaseItemManager
return libraryTypeOptions.ImageFetchers.Contains(name, StringComparison.OrdinalIgnoreCase);
}
- var itemConfig = _serverConfigurationManager.GetMetadataOptionsForType(baseItem.GetType().Name);
+ var itemConfig = this._serverConfigurationManager.GetMetadataOptionsForType(baseItem.GetType().Name);
return itemConfig is null || !itemConfig.DisabledImageFetchers.Contains(name, StringComparison.OrdinalIgnoreCase);
}
}
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index 37511329..9fb4b80b 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -27,12 +27,18 @@ namespace MediaBrowser.Controller.Channels
[JsonIgnore]
public override SourceType SourceType => SourceType.Channel;
+ ///
+ /// Determines whether this channel is visible to the specified user.
+ ///
+ /// The user.
+ /// Whether to skip the allowed tags check.
+ /// True if visible; otherwise, false.
public override bool IsVisible(User user, bool skipAllowedTagsCheck = false)
{
var blockedChannelsPreference = user.GetPreferenceValues(PreferenceKind.BlockedChannels);
if (blockedChannelsPreference.Length != 0)
{
- if (blockedChannelsPreference.Contains(Id))
+ if (blockedChannelsPreference.Contains(this.Id))
{
return false;
}
@@ -40,7 +46,7 @@ namespace MediaBrowser.Controller.Channels
else
{
if (!user.HasPermission(PermissionKind.EnableAllChannels)
- && !user.GetPreferenceValues(PreferenceKind.EnabledChannels).Contains(Id))
+ && !user.GetPreferenceValues(PreferenceKind.EnabledChannels).Contains(this.Id))
{
return false;
}
@@ -49,12 +55,17 @@ namespace MediaBrowser.Controller.Channels
return base.IsVisible(user, skipAllowedTagsCheck);
}
+ ///
+ /// Gets items from the channel.
+ ///
+ /// The items query.
+ /// The query result.
protected override QueryResult GetItemsInternal(InternalItemsQuery query)
{
try
{
query.Parent = this;
- query.ChannelIds = new Guid[] { Id };
+ query.ChannelIds = new Guid[] { this.Id };
// Don't blow up here because it could cause parent screens with other content to fail
return ChannelManager.GetChannelItemsInternal(query, new Progress(), CancellationToken.None).GetAwaiter().GetResult();
@@ -66,21 +77,42 @@ namespace MediaBrowser.Controller.Channels
}
}
+ ///
+ /// Gets the internal metadata path for this channel.
+ ///
+ /// The base path.
+ /// The internal metadata path.
protected override string GetInternalMetadataPath(string basePath)
{
- return GetInternalMetadataPath(basePath, Id);
+ return GetInternalMetadataPath(basePath, this.Id);
}
+ ///
+ /// Gets the internal metadata path for a channel with the specified ID.
+ ///
+ /// The base path.
+ /// The channel ID.
+ /// The internal metadata path.
public static string GetInternalMetadataPath(string basePath, Guid id)
{
return System.IO.Path.Combine(basePath, "channels", id.ToString("N", CultureInfo.InvariantCulture), "metadata");
}
+ ///
+ /// Determines whether this channel can be deleted.
+ ///
+ /// True if deletable; otherwise, false.
public override bool CanDelete()
{
return false;
}
+ ///
+ /// Determines whether the channel item is visible to the specified user.
+ ///
+ /// The channel item.
+ /// The user.
+ /// True if visible; otherwise, false.
internal static bool IsChannelVisible(BaseItem channelItem, User user)
{
var channel = ChannelManager.GetChannel(channelItem.ChannelId.ToString(string.Empty));
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index bcd469cb..c1a4d276 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -142,7 +142,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public SongInfo GetLookupInfo()
{
- var info = GetItemLookupInfo();
+ var info = this.GetItemLookupInfo();
info.AlbumArtists = AlbumArtists;
info.Album = Album;
diff --git a/MediaBrowser.Controller/Entities/AudioBook.cs b/MediaBrowser.Controller/Entities/AudioBook.cs
index c77d1c68..bc0e6700 100644
--- a/MediaBrowser.Controller/Entities/AudioBook.cs
+++ b/MediaBrowser.Controller/Entities/AudioBook.cs
@@ -31,36 +31,64 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public Guid SeriesId { get; set; }
+ ///
+ /// Finds the series sort name.
+ ///
+ /// The series sort name.
public string FindSeriesSortName()
{
- return SeriesName;
+ return this.SeriesName;
}
+ ///
+ /// Finds the series name.
+ ///
+ /// The series name.
public string FindSeriesName()
{
- return SeriesName;
+ return this.SeriesName;
}
+ ///
+ /// Finds the series presentation unique key.
+ ///
+ /// The series presentation unique key.
public string FindSeriesPresentationUniqueKey()
{
- return SeriesPresentationUniqueKey;
+ return this.SeriesPresentationUniqueKey;
}
+ ///
+ /// Gets the default primary image aspect ratio.
+ ///
+ /// The default primary image aspect ratio.
public override double GetDefaultPrimaryImageAspectRatio()
{
return 0;
}
+ ///
+ /// Finds the series identifier.
+ ///
+ /// The series identifier.
public Guid FindSeriesId()
{
- return SeriesId;
+ return this.SeriesId;
}
+ ///
+ /// Determines whether this audiobook can be downloaded.
+ ///
+ /// True if downloadable; otherwise, false.
public override bool CanDownload()
{
- return IsFileProtocol;
+ return this.IsFileProtocol;
}
+ ///
+ /// Gets the unrated type for blocking purposes.
+ ///
+ /// The unrated item type.
public override UnratedItem GetBlockUnratedType()
{
return UnratedItem.Book;
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 39462adf..1f9176f8 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -7263,6 +7263,13 @@ namespace MediaBrowser.Controller.MediaEncoding
return inputModifier;
}
+ ///
+ /// Attaches media source information to the encoding job state.
+ ///
+ /// The encoding job state.
+ /// The encoding options.
+ /// The media source information.
+ /// The requested URL.
public void AttachMediaSourceInfo(
EncodingJobInfo state,
EncodingOptions encodingOptions,
@@ -7327,26 +7334,26 @@ namespace MediaBrowser.Controller.MediaEncoding
requestedUrl = "test." + videoRequest.Container;
}
- videoRequest.VideoCodec = InferVideoCodec(requestedUrl);
+ videoRequest.VideoCodec = this.InferVideoCodec(requestedUrl);
}
- state.VideoStream = GetMediaStream(mediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video);
- state.SubtitleStream = GetMediaStream(mediaStreams, videoRequest.SubtitleStreamIndex, MediaStreamType.Subtitle, false);
+ state.VideoStream = this.GetMediaStream(mediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video);
+ state.SubtitleStream = this.GetMediaStream(mediaStreams, videoRequest.SubtitleStreamIndex, MediaStreamType.Subtitle, false);
state.SubtitleDeliveryMethod = videoRequest.SubtitleMethod;
- state.AudioStream = GetMediaStream(mediaStreams, videoRequest.AudioStreamIndex, MediaStreamType.Audio);
+ state.AudioStream = this.GetMediaStream(mediaStreams, videoRequest.AudioStreamIndex, MediaStreamType.Audio);
if (state.SubtitleStream is not null && !state.SubtitleStream.IsExternal)
{
state.InternalSubtitleStreamOffset = mediaStreams.Where(i => i.Type == MediaStreamType.Subtitle && !i.IsExternal).ToList().IndexOf(state.SubtitleStream);
}
- EnforceResolutionLimit(state);
+ this.EnforceResolutionLimit(state);
- NormalizeSubtitleEmbed(state);
+ this.NormalizeSubtitleEmbed(state);
}
else
{
- state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
+ state.AudioStream = this.GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
}
state.MediaSource = mediaSource;
@@ -7357,11 +7364,11 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var supportedAudioCodecsList = supportedAudioCodecs.ToList();
- ShiftAudioCodecsIfNeeded(supportedAudioCodecsList, state.AudioStream);
+ this.ShiftAudioCodecsIfNeeded(supportedAudioCodecsList, state.AudioStream);
state.SupportedAudioCodecs = supportedAudioCodecsList.ToArray();
- request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(_mediaEncoder.CanEncodeToAudioCodec)
+ request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(this._mediaEncoder.CanEncodeToAudioCodec)
?? state.SupportedAudioCodecs.FirstOrDefault();
}
@@ -7370,7 +7377,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var supportedVideoCodecsList = supportedVideoCodecs.ToList();
- ShiftVideoCodecsIfNeeded(supportedVideoCodecsList, encodingOptions);
+ this.ShiftVideoCodecsIfNeeded(supportedVideoCodecsList, encodingOptions);
state.SupportedVideoCodecs = supportedVideoCodecsList.ToArray();
@@ -7791,6 +7798,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|| (state.BaseRequest.AlwaysBurnInSubtitleWhenTranscoding && !IsCopyCodec(state.OutputVideoCodec));
}
+ ///
+ /// Gets the video sync option based on the encoder version.
+ ///
+ /// The video sync parameter.
+ /// The encoder version.
+ /// The video sync option string.
public static string GetVideoSyncOption(string videoSync, Version encoderVersion)
{
if (string.IsNullOrEmpty(videoSync))
@@ -7808,7 +7821,7 @@ namespace MediaBrowser.Controller.MediaEncoding
0 => " -fps_mode passthrough",
1 => " -fps_mode cfr",
2 => " -fps_mode vfr",
- _ => string.Empty
+ _ => string.Empty,
};
}
diff --git a/MediaBrowser.Controller/obj/project.nuget.cache b/MediaBrowser.Controller/obj/project.nuget.cache
index a8132c41..80d5e712 100644
--- a/MediaBrowser.Controller/obj/project.nuget.cache
+++ b/MediaBrowser.Controller/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "No+LvUzpMog=",
+ "dgSpecHash": "oIB4cupu3LM=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\MediaBrowser.Controller\\MediaBrowser.Controller.csproj",
"expectedPackageFiles": [
diff --git a/MediaBrowser.LocalMetadata/obj/project.nuget.cache b/MediaBrowser.LocalMetadata/obj/project.nuget.cache
index 090e8528..44ace0a6 100644
--- a/MediaBrowser.LocalMetadata/obj/project.nuget.cache
+++ b/MediaBrowser.LocalMetadata/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "MUG8U7vEPzE=",
+ "dgSpecHash": "GeC+ga1Uo2A=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\MediaBrowser.LocalMetadata\\MediaBrowser.LocalMetadata.csproj",
"expectedPackageFiles": [
diff --git a/MediaBrowser.MediaEncoding/obj/project.nuget.cache b/MediaBrowser.MediaEncoding/obj/project.nuget.cache
index 7d158cd5..68198fee 100644
--- a/MediaBrowser.MediaEncoding/obj/project.nuget.cache
+++ b/MediaBrowser.MediaEncoding/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "GTQOs1iNxFU=",
+ "dgSpecHash": "aQOA3jWvZ/0=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\MediaBrowser.MediaEncoding\\MediaBrowser.MediaEncoding.csproj",
"expectedPackageFiles": [
diff --git a/MediaBrowser.Providers/obj/project.nuget.cache b/MediaBrowser.Providers/obj/project.nuget.cache
index b799ccd6..77a580a9 100644
--- a/MediaBrowser.Providers/obj/project.nuget.cache
+++ b/MediaBrowser.Providers/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "O+ANw3v7loA=",
+ "dgSpecHash": "ncCtXCalGV4=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\MediaBrowser.Providers\\MediaBrowser.Providers.csproj",
"expectedPackageFiles": [
diff --git a/MediaBrowser.XbmcMetadata/obj/project.nuget.cache b/MediaBrowser.XbmcMetadata/obj/project.nuget.cache
index 832e5504..5452631b 100644
--- a/MediaBrowser.XbmcMetadata/obj/project.nuget.cache
+++ b/MediaBrowser.XbmcMetadata/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "rQazb3gGG1E=",
+ "dgSpecHash": "P3fDKwImSWA=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\MediaBrowser.XbmcMetadata\\MediaBrowser.XbmcMetadata.csproj",
"expectedPackageFiles": [
diff --git a/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll b/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll
index 59e5eaf4..236c2eb9 100644
Binary files a/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll and b/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll differ
diff --git a/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.pdb b/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.pdb
index 8f51f768..a976dc0a 100644
Binary files a/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.pdb and b/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.pdb differ
diff --git a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfo.cs b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfo.cs
index b55c4653..6bdec647 100644
--- a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfo.cs
+++ b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfo.cs
@@ -14,7 +14,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Jellyfin.CodeAnalysis")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
-[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+477045704e49d02668be2cddb91b218a9e70ec95")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+dbeec2e9f0c8f46c715f999e2be12d779e1fbd62")]
[assembly: System.Reflection.AssemblyProductAttribute("Jellyfin.CodeAnalysis")]
[assembly: System.Reflection.AssemblyTitleAttribute("Jellyfin.CodeAnalysis")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
diff --git a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfoInputs.cache b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfoInputs.cache
index df1c3ccc..332b05f6 100644
--- a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfoInputs.cache
+++ b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfoInputs.cache
@@ -1 +1 @@
-0aa0b87087f971012539e7d2b22ae3fc0248cc13dafe15e7394876c75cd2b839
+9034528098f49c58c86624aecd413bc8526e219cc0c6d56bad4cbb6d5ce48570
diff --git a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.csproj.AssemblyReference.cache b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.csproj.AssemblyReference.cache
index 4c5b9dad..1fd0093c 100644
Binary files a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.csproj.AssemblyReference.cache and b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.csproj.AssemblyReference.cache differ
diff --git a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll
index 59e5eaf4..236c2eb9 100644
Binary files a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll and b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll differ
diff --git a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.pdb b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.pdb
index 8f51f768..a976dc0a 100644
Binary files a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.pdb and b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.pdb differ
diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/obj/project.nuget.cache b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/obj/project.nuget.cache
index c4a00c0e..5b2c5edb 100644
--- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/obj/project.nuget.cache
+++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "7p0VjWNAkOM=",
+ "dgSpecHash": "vHGJFlfns3Y=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\src\\Jellyfin.Database\\Jellyfin.Database.Providers.Sqlite\\Jellyfin.Database.Providers.Sqlite.csproj",
"expectedPackageFiles": [
diff --git a/src/Jellyfin.Drawing.Skia/obj/project.nuget.cache b/src/Jellyfin.Drawing.Skia/obj/project.nuget.cache
index ef341c73..a88faec5 100644
--- a/src/Jellyfin.Drawing.Skia/obj/project.nuget.cache
+++ b/src/Jellyfin.Drawing.Skia/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "HMW40QmobtY=",
+ "dgSpecHash": "Fpoz11tqLl0=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\src\\Jellyfin.Drawing.Skia\\Jellyfin.Drawing.Skia.csproj",
"expectedPackageFiles": [
diff --git a/src/Jellyfin.Drawing/ImageProcessor.cs b/src/Jellyfin.Drawing/ImageProcessor.cs
index a84f0034..12450cb0 100644
--- a/src/Jellyfin.Drawing/ImageProcessor.cs
+++ b/src/Jellyfin.Drawing/ImageProcessor.cs
@@ -64,10 +64,10 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
IImageEncoder imageEncoder,
IServerConfigurationManager config)
{
- _logger = logger;
- _fileSystem = fileSystem;
- _imageEncoder = imageEncoder;
- _appPaths = appPaths;
+ this._logger = logger;
+ this._fileSystem = fileSystem;
+ this._imageEncoder = imageEncoder;
+ this._appPaths = appPaths;
var semaphoreCount = config.Configuration.ParallelImageEncodingLimit;
if (semaphoreCount < 1)
@@ -75,10 +75,10 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
semaphoreCount = Environment.ProcessorCount;
}
- _parallelEncodingLimit = new(semaphoreCount);
+ this._parallelEncodingLimit = new(semaphoreCount);
}
- private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images");
+ private string ResizedImageCachePath => Path.Combine(this._appPaths.ImageCachePath, "resized-images");
///
public IReadOnlyCollection SupportedInputFormats =>
@@ -113,11 +113,11 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
};
///
- public bool SupportsImageCollageCreation => _imageEncoder.SupportsImageCollageCreation;
+ public bool SupportsImageCollageCreation => this._imageEncoder.SupportsImageCollageCreation;
///
public IReadOnlyCollection GetSupportedImageOutputFormats()
- => _imageEncoder.SupportedOutputFormats;
+ => this._imageEncoder.SupportedOutputFormats;
///
public async Task<(string Path, string? MimeType, DateTime DateModified)> ProcessImage(ImageProcessingOptions options)
@@ -134,12 +134,12 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
}
var mimeType = MimeTypes.GetMimeType(originalImagePath);
- if (!_imageEncoder.SupportsImageEncoding)
+ if (!this._imageEncoder.SupportsImageEncoding)
{
return (originalImagePath, mimeType, dateModified);
}
- var supportedImageInfo = await GetSupportedImage(originalImagePath, dateModified).ConfigureAwait(false);
+ var supportedImageInfo = await this.GetSupportedImage(originalImagePath, dateModified).ConfigureAwait(false);
originalImagePath = supportedImageInfo.Path;
// Original file doesn't exist, or original file is gif.
@@ -179,8 +179,8 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
int quality = options.Quality;
- ImageFormat outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
- string cacheFilePath = GetCacheFilePath(
+ ImageFormat outputFormat = this.GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
+ string cacheFilePath = this.GetCacheFilePath(
originalImagePath,
options.Width,
options.Height,
@@ -204,9 +204,9 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
string resultPath;
// Limit number of parallel (more precisely: concurrent) image encodings to prevent a high memory usage
- using (await _parallelEncodingLimit.LockAsync().ConfigureAwait(false))
+ using (await this._parallelEncodingLimit.LockAsync().ConfigureAwait(false))
{
- resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat);
+ resultPath = this._imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat);
}
if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
@@ -215,19 +215,19 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
}
}
- return (cacheFilePath, outputFormat.GetMimeType(), _fileSystem.GetLastWriteTimeUtc(cacheFilePath));
+ return (cacheFilePath, outputFormat.GetMimeType(), this._fileSystem.GetLastWriteTimeUtc(cacheFilePath));
}
catch (Exception ex)
{
// If it fails for whatever reason, return the original image
- _logger.LogError(ex, "Error encoding image");
+ this._logger.LogError(ex, "Error encoding image");
return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
}
private ImageFormat GetOutputFormat(IReadOnlyCollection clientSupportedFormats, bool requiresTransparency)
{
- var serverFormats = GetSupportedImageOutputFormats();
+ var serverFormats = this.GetSupportedImageOutputFormats();
// Client doesn't care about format, so start with webp if supported
if (serverFormats.Contains(ImageFormat.Webp) && clientSupportedFormats.Contains(ImageFormat.Webp))
@@ -354,7 +354,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
filename.Append(",v=");
filename.Append(Version);
- return GetCachePath(ResizedImageCachePath, filename.ToString(), format.GetExtension());
+ return this.GetCachePath(this.ResizedImageCachePath, filename.ToString(), format.GetExtension());
}
///
@@ -369,9 +369,9 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
}
string path = info.Path;
- _logger.LogDebug("Getting image size for item {ItemType} {Path}", item.GetType().Name, path);
+ this._logger.LogDebug("Getting image size for item {ItemType} {Path}", item.GetType().Name, path);
- ImageDimensions size = GetImageDimensions(path);
+ ImageDimensions size = this.GetImageDimensions(path);
info.Width = size.Width;
info.Height = size.Height;
@@ -380,13 +380,13 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
///
public ImageDimensions GetImageDimensions(string path)
- => _imageEncoder.GetImageSize(path);
+ => this._imageEncoder.GetImageSize(path);
///
public string GetImageBlurHash(string path)
{
- var size = GetImageDimensions(path);
- return GetImageBlurHash(path, size);
+ var size = this.GetImageDimensions(path);
+ return this.GetImageBlurHash(path, size);
}
///
@@ -406,7 +406,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
int xComp = Math.Min((int)xCompF + 1, 9);
int yComp = Math.Min((int)yCompF + 1, 9);
- return _imageEncoder.GetImageBlurHash(xComp, yComp, path);
+ return this._imageEncoder.GetImageBlurHash(xComp, yComp, path);
}
///
@@ -415,11 +415,11 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
///
public string GetImageCacheTag(BaseItem item, ItemImageInfo image)
- => GetImageCacheTag(item.Path, image.DateModified);
+ => this.GetImageCacheTag(item.Path, image.DateModified);
///
public string GetImageCacheTag(BaseItemDto item, ItemImageInfo image)
- => GetImageCacheTag(item.Path, image.DateModified);
+ => this.GetImageCacheTag(item.Path, image.DateModified);
///
public string? GetImageCacheTag(BaseItemDto item, ChapterInfo chapter)
@@ -429,7 +429,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
return null;
}
- return GetImageCacheTag(item.Path, chapter.ImageDateModified);
+ return this.GetImageCacheTag(item.Path, chapter.ImageDateModified);
}
///
@@ -440,7 +440,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
return null;
}
- return GetImageCacheTag(item, new ItemImageInfo
+ return this.GetImageCacheTag(item, new ItemImageInfo
{
Path = chapter.ImagePath,
Type = ImageType.Chapter,
@@ -456,7 +456,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
return null;
}
- return GetImageCacheTag(user.ProfileImage.Path, user.ProfileImage.LastModified);
+ return this.GetImageCacheTag(user.ProfileImage.Path, user.ProfileImage.LastModified);
}
private Task<(string Path, DateTime DateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
@@ -494,7 +494,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
var filename = uniqueName.GetMD5() + fileExtension;
- return GetCachePath(path, filename);
+ return this.GetCachePath(path, filename);
}
///
@@ -528,28 +528,28 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
///
public void CreateImageCollage(ImageCollageOptions options, string? libraryName)
{
- _logger.LogDebug("Creating image collage and saving to {Path}", options.OutputPath);
+ this._logger.LogDebug("Creating image collage and saving to {Path}", options.OutputPath);
- _imageEncoder.CreateImageCollage(options, libraryName);
+ this._imageEncoder.CreateImageCollage(options, libraryName);
- _logger.LogDebug("Completed creation of image collage and saved to {Path}", options.OutputPath);
+ this._logger.LogDebug("Completed creation of image collage and saved to {Path}", options.OutputPath);
}
///
public void Dispose()
{
- if (_disposed)
+ if (this._disposed)
{
return;
}
- if (_imageEncoder is IDisposable disposable)
+ if (this._imageEncoder is IDisposable disposable)
{
disposable.Dispose();
}
- _parallelEncodingLimit?.Dispose();
+ this._parallelEncodingLimit?.Dispose();
- _disposed = true;
+ this._disposed = true;
}
}
diff --git a/src/Jellyfin.Drawing/obj/project.nuget.cache b/src/Jellyfin.Drawing/obj/project.nuget.cache
index 63719595..522e6462 100644
--- a/src/Jellyfin.Drawing/obj/project.nuget.cache
+++ b/src/Jellyfin.Drawing/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "kfdiYX/qdMo=",
+ "dgSpecHash": "Vcdm+k15Tts=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\src\\Jellyfin.Drawing\\Jellyfin.Drawing.csproj",
"expectedPackageFiles": [
diff --git a/src/Jellyfin.LiveTv/obj/project.nuget.cache b/src/Jellyfin.LiveTv/obj/project.nuget.cache
index 96bf1989..ab1ebe5a 100644
--- a/src/Jellyfin.LiveTv/obj/project.nuget.cache
+++ b/src/Jellyfin.LiveTv/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "Wq1Uahcka68=",
+ "dgSpecHash": "9I/zz4fLYTY=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\src\\Jellyfin.LiveTv\\Jellyfin.LiveTv.csproj",
"expectedPackageFiles": [
diff --git a/src/Jellyfin.MediaEncoding.Hls/obj/project.nuget.cache b/src/Jellyfin.MediaEncoding.Hls/obj/project.nuget.cache
index 86ecdc7f..2fde37c8 100644
--- a/src/Jellyfin.MediaEncoding.Hls/obj/project.nuget.cache
+++ b/src/Jellyfin.MediaEncoding.Hls/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "2kUNnZdwGG8=",
+ "dgSpecHash": "svddOISkg9E=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\src\\Jellyfin.MediaEncoding.Hls\\Jellyfin.MediaEncoding.Hls.csproj",
"expectedPackageFiles": [
diff --git a/src/Jellyfin.MediaEncoding.Keyframes/FfProbe/FfProbeKeyframeExtractor.cs b/src/Jellyfin.MediaEncoding.Keyframes/FfProbe/FfProbeKeyframeExtractor.cs
index b75adc77..5975aebd 100644
--- a/src/Jellyfin.MediaEncoding.Keyframes/FfProbe/FfProbeKeyframeExtractor.cs
+++ b/src/Jellyfin.MediaEncoding.Keyframes/FfProbe/FfProbeKeyframeExtractor.cs
@@ -76,60 +76,62 @@ public static class FfProbeKeyframeExtractor
}
}
+ ///
+ /// Parses the keyframe data from the FFProbe stream.
+ ///
+ /// The stream reader containing FFProbe output.
+ /// The parsed keyframe data.
internal static KeyframeData ParseStream(StreamReader reader)
{
var keyframes = new List();
double streamDuration = 0;
double formatDuration = 0;
- using (reader)
+ while (!reader.EndOfStream)
{
- while (!reader.EndOfStream)
+ var line = reader.ReadLine().AsSpan();
+ if (line.IsEmpty)
{
- var line = reader.ReadLine().AsSpan();
- if (line.IsEmpty)
- {
- continue;
- }
+ continue;
+ }
- var firstComma = line.IndexOf(',');
- var lineType = line[..firstComma];
- var rest = line[(firstComma + 1)..];
- if (lineType.Equals("packet", StringComparison.OrdinalIgnoreCase))
+ var firstComma = line.IndexOf(',');
+ var lineType = line[..firstComma];
+ var rest = line[(firstComma + 1)..];
+ if (lineType.Equals("packet", StringComparison.OrdinalIgnoreCase))
+ {
+ // Split time and flags from the packet line. Example line: packet,7169.079000,K_
+ var secondComma = rest.IndexOf(',');
+ var ptsTime = rest[..secondComma];
+ var flags = rest[(secondComma + 1)..];
+ if (flags.StartsWith("K_"))
{
- // Split time and flags from the packet line. Example line: packet,7169.079000,K_
- var secondComma = rest.IndexOf(',');
- var ptsTime = rest[..secondComma];
- var flags = rest[(secondComma + 1)..];
- if (flags.StartsWith("K_"))
+ if (double.TryParse(ptsTime, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var keyframe))
{
- if (double.TryParse(ptsTime, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var keyframe))
- {
- // Have to manually convert to ticks to avoid rounding errors as TimeSpan is only precise down to 1 ms when converting double.
- keyframes.Add(Convert.ToInt64(keyframe * TimeSpan.TicksPerSecond));
- }
- }
- }
- else if (lineType.Equals("stream", StringComparison.OrdinalIgnoreCase))
- {
- if (double.TryParse(rest, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var streamDurationResult))
- {
- streamDuration = streamDurationResult;
- }
- }
- else if (lineType.Equals("format", StringComparison.OrdinalIgnoreCase))
- {
- if (double.TryParse(rest, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var formatDurationResult))
- {
- formatDuration = formatDurationResult;
+ // Have to manually convert to ticks to avoid rounding errors as TimeSpan is only precise down to 1 ms when converting double.
+ keyframes.Add(Convert.ToInt64(keyframe * TimeSpan.TicksPerSecond));
}
}
}
-
- // Prefer the stream duration as it should be more accurate
- var duration = streamDuration > 0 ? streamDuration : formatDuration;
-
- return new KeyframeData(TimeSpan.FromSeconds(duration).Ticks, keyframes);
+ else if (lineType.Equals("stream", StringComparison.OrdinalIgnoreCase))
+ {
+ if (double.TryParse(rest, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var streamDurationResult))
+ {
+ streamDuration = streamDurationResult;
+ }
+ }
+ else if (lineType.Equals("format", StringComparison.OrdinalIgnoreCase))
+ {
+ if (double.TryParse(rest, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var formatDurationResult))
+ {
+ formatDuration = formatDurationResult;
+ }
+ }
}
+
+ // Prefer the stream duration as it should be more accurate
+ var duration = streamDuration > 0 ? streamDuration : formatDuration;
+
+ return new KeyframeData(TimeSpan.FromSeconds(duration).Ticks, keyframes);
}
}
diff --git a/src/Jellyfin.MediaEncoding.Keyframes/KeyframeData.cs b/src/Jellyfin.MediaEncoding.Keyframes/KeyframeData.cs
index 70b7269a..e4b7bb5b 100644
--- a/src/Jellyfin.MediaEncoding.Keyframes/KeyframeData.cs
+++ b/src/Jellyfin.MediaEncoding.Keyframes/KeyframeData.cs
@@ -18,8 +18,8 @@ public class KeyframeData
/// The video keyframes in ticks.
public KeyframeData(long totalDuration, IReadOnlyList keyframeTicks)
{
- TotalDuration = totalDuration;
- KeyframeTicks = keyframeTicks;
+ this.TotalDuration = totalDuration;
+ this.KeyframeTicks = keyframeTicks;
}
///
diff --git a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Extensions/EbmlReaderExtensions.cs b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Extensions/EbmlReaderExtensions.cs
index 69f89158..f9094146 100644
--- a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Extensions/EbmlReaderExtensions.cs
+++ b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Extensions/EbmlReaderExtensions.cs
@@ -70,6 +70,7 @@ internal static class EbmlReaderExtensions
long? tracksPosition = null;
long? cuesPosition = null;
long? infoPosition = null;
+
// The first element should be a SeekHead otherwise we'll have to search manually
if (!reader.FindElement(MatroskaConstants.SeekHead))
{
@@ -128,6 +129,7 @@ internal static class EbmlReaderExtensions
double? duration = null;
reader.EnterContainer();
+
// Mandatory element
reader.FindElement(MatroskaConstants.TimestampScale);
var timestampScale = reader.ReadUInt();
@@ -158,6 +160,7 @@ internal static class EbmlReaderExtensions
while (reader.FindElement(MatroskaConstants.TrackEntry))
{
reader.EnterContainer();
+
// Mandatory element
reader.FindElement(MatroskaConstants.TrackNumber);
var trackNumber = reader.ReadUInt();
diff --git a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/MatroskaConstants.cs b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/MatroskaConstants.cs
index 84a6df41..358fe2f3 100644
--- a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/MatroskaConstants.cs
+++ b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/MatroskaConstants.cs
@@ -9,26 +9,88 @@ namespace Jellyfin.MediaEncoding.Keyframes.Matroska;
///
public static class MatroskaConstants
{
+ ///
+ /// The Matroska segment container identifier.
+ ///
internal const ulong SegmentContainer = 0x18538067;
+ ///
+ /// The Matroska seek head identifier.
+ ///
internal const ulong SeekHead = 0x114D9B74;
+
+ ///
+ /// The Matroska seek identifier.
+ ///
internal const ulong Seek = 0x4DBB;
+ ///
+ /// The Matroska info identifier.
+ ///
internal const ulong Info = 0x1549A966;
+
+ ///
+ /// The Matroska timestamp scale identifier.
+ ///
internal const ulong TimestampScale = 0x2AD7B1;
+
+ ///
+ /// The Matroska duration identifier.
+ ///
internal const ulong Duration = 0x4489;
+ ///
+ /// The Matroska tracks identifier.
+ ///
internal const ulong Tracks = 0x1654AE6B;
+
+ ///
+ /// The Matroska track entry identifier.
+ ///
internal const ulong TrackEntry = 0xAE;
+
+ ///
+ /// The Matroska track number identifier.
+ ///
internal const ulong TrackNumber = 0xD7;
+
+ ///
+ /// The Matroska track type identifier.
+ ///
internal const ulong TrackType = 0x83;
+ ///
+ /// The Matroska video track type value.
+ ///
internal const ulong TrackTypeVideo = 0x1;
+
+ ///
+ /// The Matroska subtitle track type value.
+ ///
internal const ulong TrackTypeSubtitle = 0x11;
+ ///
+ /// The Matroska cues identifier.
+ ///
internal const ulong Cues = 0x1C53BB6B;
+
+ ///
+ /// The Matroska cue time identifier.
+ ///
internal const ulong CueTime = 0xB3;
+
+ ///
+ /// The Matroska cue point identifier.
+ ///
internal const ulong CuePoint = 0xBB;
+
+ ///
+ /// The Matroska cue track positions identifier.
+ ///
internal const ulong CueTrackPositions = 0xB7;
+
+ ///
+ /// The Matroska cue point track number identifier.
+ ///
internal const ulong CuePointTrackNumber = 0xF7;
}
diff --git a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/MatroskaKeyframeExtractor.cs b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/MatroskaKeyframeExtractor.cs
index cb6aa3b2..50f06e08 100644
--- a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/MatroskaKeyframeExtractor.cs
+++ b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/MatroskaKeyframeExtractor.cs
@@ -27,6 +27,7 @@ public static class MatroskaKeyframeExtractor
using var reader = new EbmlReader(stream);
var seekHead = reader.ReadSeekHead();
+
// External lib does not support seeking backwards (yet)
Info info;
ulong videoTrackNumber;
@@ -49,6 +50,7 @@ public static class MatroskaKeyframeExtractor
{
reader.EnterContainer();
ulong? trackNumber = null;
+
// Mandatory element
reader.FindElement(MatroskaConstants.CueTime);
var cueTime = reader.ReadUInt();
diff --git a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Models/Info.cs b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Models/Info.cs
index 8c5722d1..109c0881 100644
--- a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Models/Info.cs
+++ b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Models/Info.cs
@@ -16,8 +16,8 @@ internal class Info
/// The duration of the entire file.
public Info(long timestampScale, double? duration)
{
- TimestampScale = timestampScale;
- Duration = duration;
+ this.TimestampScale = timestampScale;
+ this.Duration = duration;
}
///
diff --git a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Models/SeekHead.cs b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Models/SeekHead.cs
index 6eabc8a8..a34d0815 100644
--- a/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Models/SeekHead.cs
+++ b/src/Jellyfin.MediaEncoding.Keyframes/Matroska/Models/SeekHead.cs
@@ -17,9 +17,9 @@ internal class SeekHead
/// The relative file position of the cues segment.
public SeekHead(long infoPosition, long tracksPosition, long cuesPosition)
{
- InfoPosition = infoPosition;
- TracksPosition = tracksPosition;
- CuesPosition = cuesPosition;
+ this.InfoPosition = infoPosition;
+ this.TracksPosition = tracksPosition;
+ this.CuesPosition = cuesPosition;
}
///
diff --git a/src/Jellyfin.MediaEncoding.Keyframes/obj/project.nuget.cache b/src/Jellyfin.MediaEncoding.Keyframes/obj/project.nuget.cache
index f6c37485..e5613e27 100644
--- a/src/Jellyfin.MediaEncoding.Keyframes/obj/project.nuget.cache
+++ b/src/Jellyfin.MediaEncoding.Keyframes/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "mTVFQQSIGo8=",
+ "dgSpecHash": "fWFpFkhudto=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\src\\Jellyfin.MediaEncoding.Keyframes\\Jellyfin.MediaEncoding.Keyframes.csproj",
"expectedPackageFiles": [
diff --git a/src/Jellyfin.Networking/obj/project.nuget.cache b/src/Jellyfin.Networking/obj/project.nuget.cache
index bde2e2ce..c0129512 100644
--- a/src/Jellyfin.Networking/obj/project.nuget.cache
+++ b/src/Jellyfin.Networking/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "o8ef9/49oOU=",
+ "dgSpecHash": "nYThmTXT+N4=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\src\\Jellyfin.Networking\\Jellyfin.Networking.csproj",
"expectedPackageFiles": [
diff --git a/tests/Jellyfin.Api.Tests/obj/project.nuget.cache b/tests/Jellyfin.Api.Tests/obj/project.nuget.cache
index 5cc91304..5c5091f3 100644
--- a/tests/Jellyfin.Api.Tests/obj/project.nuget.cache
+++ b/tests/Jellyfin.Api.Tests/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "I6cvgut0KE0=",
+ "dgSpecHash": "jz3od75Vj9o=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\tests\\Jellyfin.Api.Tests\\Jellyfin.Api.Tests.csproj",
"expectedPackageFiles": [
diff --git a/tests/Jellyfin.Common.Tests/obj/project.nuget.cache b/tests/Jellyfin.Common.Tests/obj/project.nuget.cache
index 1562062a..f4d4c8d5 100644
--- a/tests/Jellyfin.Common.Tests/obj/project.nuget.cache
+++ b/tests/Jellyfin.Common.Tests/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "rSTC0c4hKeg=",
+ "dgSpecHash": "D3+az8yIj/g=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\tests\\Jellyfin.Common.Tests\\Jellyfin.Common.Tests.csproj",
"expectedPackageFiles": [
diff --git a/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs b/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs
index 0e1e1c63..97b1610a 100644
--- a/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs
+++ b/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs
@@ -13,8 +13,17 @@ namespace Jellyfin.Controller.Tests
using Moq;
using Xunit;
+ ///
+ /// Tests for .
+ ///
public class BaseItemManagerTests
{
+ ///
+ /// Tests that IsMetadataFetcherEnabled checks library and server configuration options.
+ ///
+ /// The type of item to test.
+ /// The name of the metadata fetcher.
+ /// The expected result.
[Theory]
[InlineData(typeof(Book), "LibraryEnabled", true)]
[InlineData(typeof(Book), "LibraryDisabled", false)]
@@ -24,30 +33,36 @@ namespace Jellyfin.Controller.Tests
{
BaseItem item = (BaseItem)Activator.CreateInstance(itemType)!;
- var libraryTypeOptions = itemType == typeof(Book)
+ TypeOptions? libraryTypeOptions = itemType == typeof(Book)
? new TypeOptions
{
Type = "Book",
- MetadataFetchers = new[] { "LibraryEnabled" }
+ MetadataFetchers = ["LibraryEnabled"],
}
: null;
- var serverConfiguration = new ServerConfiguration();
- foreach (var typeConfig in serverConfiguration.MetadataOptions)
+ ServerConfiguration serverConfiguration = new();
+ foreach (MetadataOptions typeConfig in serverConfiguration.MetadataOptions)
{
- typeConfig.DisabledMetadataFetchers = new[] { "ServerDisabled" };
+ typeConfig.DisabledMetadataFetchers = ["ServerDisabled"];
}
- var serverConfigurationManager = new Mock();
- serverConfigurationManager.Setup(scm => scm.Configuration)
+ Mock serverConfigurationManager = new();
+ _ = serverConfigurationManager.Setup(scm => scm.Configuration)
.Returns(serverConfiguration);
- var baseItemManager = new BaseItemManager(serverConfigurationManager.Object);
- var actual = baseItemManager.IsMetadataFetcherEnabled(item, libraryTypeOptions, fetcherName);
+ BaseItemManager baseItemManager = new(serverConfigurationManager.Object);
+ bool actual = baseItemManager.IsMetadataFetcherEnabled(item, libraryTypeOptions, fetcherName);
Assert.Equal(expected, actual);
}
+ ///
+ /// Tests that IsImageFetcherEnabled checks library and server configuration options.
+ ///
+ /// The type of item to test.
+ /// The name of the image fetcher.
+ /// The expected result.
[Theory]
[InlineData(typeof(Book), "LibraryEnabled", true)]
[InlineData(typeof(Book), "LibraryDisabled", false)]
@@ -57,26 +72,26 @@ namespace Jellyfin.Controller.Tests
{
BaseItem item = (BaseItem)Activator.CreateInstance(itemType)!;
- var libraryTypeOptions = itemType == typeof(Book)
+ TypeOptions? libraryTypeOptions = itemType == typeof(Book)
? new TypeOptions
{
Type = "Book",
- ImageFetchers = new[] { "LibraryEnabled" }
+ ImageFetchers = ["LibraryEnabled"],
}
: null;
- var serverConfiguration = new ServerConfiguration();
- foreach (var typeConfig in serverConfiguration.MetadataOptions)
+ ServerConfiguration serverConfiguration = new();
+ foreach (MetadataOptions typeConfig in serverConfiguration.MetadataOptions)
{
- typeConfig.DisabledImageFetchers = new[] { "ServerDisabled" };
+ typeConfig.DisabledImageFetchers = ["ServerDisabled"];
}
- var serverConfigurationManager = new Mock();
- serverConfigurationManager.Setup(scm => scm.Configuration)
+ Mock serverConfigurationManager = new();
+ _ = serverConfigurationManager.Setup(scm => scm.Configuration)
.Returns(serverConfiguration);
- var baseItemManager = new BaseItemManager(serverConfigurationManager.Object);
- var actual = baseItemManager.IsImageFetcherEnabled(item, libraryTypeOptions, fetcherName);
+ BaseItemManager baseItemManager = new(serverConfigurationManager.Object);
+ bool actual = baseItemManager.IsImageFetcherEnabled(item, libraryTypeOptions, fetcherName);
Assert.Equal(expected, actual);
}
diff --git a/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs b/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs
index 319dcec2..a11859d3 100644
--- a/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs
+++ b/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs
@@ -4,124 +4,140 @@
namespace Jellyfin.Controller.Tests
{
+ using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using Moq;
using Xunit;
+ ///
+ /// Tests for .
+ ///
public class DirectoryServiceTests
{
private const string LowerCasePath = "/music/someartist";
private const string UpperCasePath = "/music/SOMEARTIST";
- private static readonly FileSystemMetadata[] _lowerCaseFileSystemMetadata =
- {
+ private static readonly FileSystemMetadata[] LowerCaseFileSystemMetadata =
+ [
new()
{
FullName = LowerCasePath + "/Artwork",
- IsDirectory = true
+ IsDirectory = true,
},
new()
{
FullName = LowerCasePath + "/Some Other Folder",
- IsDirectory = true
+ IsDirectory = true,
},
new()
{
FullName = LowerCasePath + "/Song 2.mp3",
- IsDirectory = false
+ IsDirectory = false,
},
new()
{
FullName = LowerCasePath + "/Song 3.mp3",
- IsDirectory = false
- }
- };
+ IsDirectory = false,
+ },
+ ];
- private static readonly FileSystemMetadata[] _upperCaseFileSystemMetadata =
- {
+ private static readonly FileSystemMetadata[] UpperCaseFileSystemMetadata =
+ [
new()
{
FullName = UpperCasePath + "/Lyrics",
- IsDirectory = true
+ IsDirectory = true,
},
new()
{
FullName = UpperCasePath + "/Song 1.mp3",
- IsDirectory = false
- }
- };
+ IsDirectory = false,
+ },
+ ];
+ ///
+ /// Tests that GetFileSystemEntries caches entries for paths with different casing.
+ ///
[Fact]
public void GetFileSystemEntries_GivenPathsWithDifferentCasing_CachesAll()
{
- var fileSystemMock = new Mock();
- fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(_upperCaseFileSystemMetadata);
- fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(_lowerCaseFileSystemMetadata);
- var directoryService = new DirectoryService(fileSystemMock.Object);
+ Mock fileSystemMock = new();
+ _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(UpperCaseFileSystemMetadata);
+ _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(LowerCaseFileSystemMetadata);
+ DirectoryService directoryService = new(fileSystemMock.Object);
- var upperCaseResult = directoryService.GetFileSystemEntries(UpperCasePath);
- var lowerCaseResult = directoryService.GetFileSystemEntries(LowerCasePath);
+ FileSystemMetadata[] upperCaseResult = directoryService.GetFileSystemEntries(UpperCasePath);
+ FileSystemMetadata[] lowerCaseResult = directoryService.GetFileSystemEntries(LowerCasePath);
- Assert.Equal(_upperCaseFileSystemMetadata, upperCaseResult);
- Assert.Equal(_lowerCaseFileSystemMetadata, lowerCaseResult);
+ Assert.Equal(UpperCaseFileSystemMetadata, upperCaseResult);
+ Assert.Equal(LowerCaseFileSystemMetadata, lowerCaseResult);
}
+ ///
+ /// Tests that GetFiles returns correct files for paths with different casing.
+ ///
[Fact]
public void GetFiles_GivenPathsWithDifferentCasing_ReturnsCorrectFiles()
{
- var fileSystemMock = new Mock();
- fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(_upperCaseFileSystemMetadata);
- fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(_lowerCaseFileSystemMetadata);
- var directoryService = new DirectoryService(fileSystemMock.Object);
+ Mock fileSystemMock = new();
+ _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(UpperCaseFileSystemMetadata);
+ _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(LowerCaseFileSystemMetadata);
+ DirectoryService directoryService = new(fileSystemMock.Object);
- var upperCaseResult = directoryService.GetFiles(UpperCasePath);
- var lowerCaseResult = directoryService.GetFiles(LowerCasePath);
+ List upperCaseResult = directoryService.GetFiles(UpperCasePath);
+ List lowerCaseResult = directoryService.GetFiles(LowerCasePath);
- Assert.Equal(_upperCaseFileSystemMetadata.Where(f => !f.IsDirectory), upperCaseResult);
- Assert.Equal(_lowerCaseFileSystemMetadata.Where(f => !f.IsDirectory), lowerCaseResult);
+ Assert.Equal(UpperCaseFileSystemMetadata.Where(f => !f.IsDirectory), upperCaseResult);
+ Assert.Equal(LowerCaseFileSystemMetadata.Where(f => !f.IsDirectory), lowerCaseResult);
}
+ ///
+ /// Tests that GetDirectories returns correct directories for paths with different casing.
+ ///
[Fact]
public void GetDirectories_GivenPathsWithDifferentCasing_ReturnsCorrectDirectories()
{
- var fileSystemMock = new Mock();
- fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(_upperCaseFileSystemMetadata);
- fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(_lowerCaseFileSystemMetadata);
- var directoryService = new DirectoryService(fileSystemMock.Object);
+ Mock fileSystemMock = new();
+ _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(UpperCaseFileSystemMetadata);
+ _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(LowerCaseFileSystemMetadata);
+ DirectoryService directoryService = new(fileSystemMock.Object);
- var upperCaseResult = directoryService.GetDirectories(UpperCasePath);
- var lowerCaseResult = directoryService.GetDirectories(LowerCasePath);
+ List upperCaseResult = directoryService.GetDirectories(UpperCasePath);
+ List lowerCaseResult = directoryService.GetDirectories(LowerCasePath);
- Assert.Equal(_upperCaseFileSystemMetadata.Where(f => f.IsDirectory), upperCaseResult);
- Assert.Equal(_lowerCaseFileSystemMetadata.Where(f => f.IsDirectory), lowerCaseResult);
+ Assert.Equal(UpperCaseFileSystemMetadata.Where(f => f.IsDirectory), upperCaseResult);
+ Assert.Equal(LowerCaseFileSystemMetadata.Where(f => f.IsDirectory), lowerCaseResult);
}
+ ///
+ /// Tests that GetFile returns correct file for paths with different casing.
+ ///
[Fact]
public void GetFile_GivenFilePathsWithDifferentCasing_ReturnsCorrectFile()
{
const string lowerCasePath = "/music/someartist/song 1.mp3";
- var lowerCaseFileSystemMetadata = new FileSystemMetadata
+ FileSystemMetadata lowerCaseFileSystemMetadata = new()
{
FullName = lowerCasePath,
- Exists = true
+ Exists = true,
};
const string upperCasePath = "/music/SOMEARTIST/SONG 1.mp3";
- var upperCaseFileSystemMetadata = new FileSystemMetadata
+ FileSystemMetadata upperCaseFileSystemMetadata = new()
{
FullName = upperCasePath,
- Exists = false
+ Exists = false,
};
- var fileSystemMock = new Mock();
- fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata);
- fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata);
- var directoryService = new DirectoryService(fileSystemMock.Object);
+ Mock fileSystemMock = new();
+ _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata);
+ _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata);
+ DirectoryService directoryService = new(fileSystemMock.Object);
- var lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath);
- var lowerCaseFileResult = directoryService.GetFile(lowerCasePath);
- var upperCaseDirResult = directoryService.GetDirectory(upperCasePath);
- var upperCaseFileResult = directoryService.GetFile(upperCasePath);
+ FileSystemMetadata? lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath);
+ FileSystemMetadata? lowerCaseFileResult = directoryService.GetFile(lowerCasePath);
+ FileSystemMetadata? upperCaseDirResult = directoryService.GetDirectory(upperCasePath);
+ FileSystemMetadata? upperCaseFileResult = directoryService.GetFile(upperCasePath);
Assert.Null(lowerCaseDirResult);
Assert.Equal(lowerCaseFileSystemMetadata, lowerCaseFileResult);
@@ -129,32 +145,35 @@ namespace Jellyfin.Controller.Tests
Assert.Null(upperCaseFileResult);
}
+ ///
+ /// Tests that GetDirectory returns correct directory for paths with different casing.
+ ///
[Fact]
public void GetDirectory_GivenFilePathsWithDifferentCasing_ReturnsCorrectDirectory()
{
const string lowerCasePath = "/music/someartist/Lyrics";
- var lowerCaseFileSystemMetadata = new FileSystemMetadata
+ FileSystemMetadata lowerCaseFileSystemMetadata = new()
{
FullName = lowerCasePath,
IsDirectory = true,
- Exists = true
+ Exists = true,
};
const string upperCasePath = "/music/SOMEARTIST/LYRICS";
- var upperCaseFileSystemMetadata = new FileSystemMetadata
+ FileSystemMetadata upperCaseFileSystemMetadata = new()
{
FullName = upperCasePath,
IsDirectory = true,
- Exists = false
+ Exists = false,
};
- var fileSystemMock = new Mock();
- fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata);
- fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata);
- var directoryService = new DirectoryService(fileSystemMock.Object);
+ Mock fileSystemMock = new();
+ _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata);
+ _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata);
+ DirectoryService directoryService = new(fileSystemMock.Object);
- var lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath);
- var lowerCaseFileResult = directoryService.GetFile(lowerCasePath);
- var upperCaseDirResult = directoryService.GetDirectory(upperCasePath);
- var upperCaseFileResult = directoryService.GetFile(upperCasePath);
+ FileSystemMetadata? lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath);
+ FileSystemMetadata? lowerCaseFileResult = directoryService.GetFile(lowerCasePath);
+ FileSystemMetadata? upperCaseDirResult = directoryService.GetDirectory(upperCasePath);
+ FileSystemMetadata? upperCaseFileResult = directoryService.GetFile(upperCasePath);
Assert.Equal(lowerCaseFileSystemMetadata, lowerCaseDirResult);
Assert.Null(lowerCaseFileResult);
@@ -162,92 +181,101 @@ namespace Jellyfin.Controller.Tests
Assert.Null(upperCaseFileResult);
}
+ ///
+ /// Tests that GetFile returns cached file when the path is already cached.
+ ///
[Fact]
public void GetFile_GivenCachedPath_ReturnsCachedFile()
{
const string path = "/music/someartist/song 1.mp3";
- var cachedFileSystemMetadata = new FileSystemMetadata
+ FileSystemMetadata cachedFileSystemMetadata = new()
{
FullName = path,
- Exists = true
+ Exists = true,
};
- var newFileSystemMetadata = new FileSystemMetadata
+ FileSystemMetadata newFileSystemMetadata = new()
{
FullName = "/music/SOMEARTIST/song 1.mp3",
- Exists = true
+ Exists = true,
};
- var fileSystemMock = new Mock();
- fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(cachedFileSystemMetadata);
- var directoryService = new DirectoryService(fileSystemMock.Object);
+ Mock fileSystemMock = new();
+ _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(cachedFileSystemMetadata);
+ DirectoryService directoryService = new(fileSystemMock.Object);
- var result = directoryService.GetFile(path);
- fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(newFileSystemMetadata);
- var secondResult = directoryService.GetFile(path);
+ FileSystemMetadata? result = directoryService.GetFile(path);
+ _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(newFileSystemMetadata);
+ FileSystemMetadata? secondResult = directoryService.GetFile(path);
Assert.Equivalent(cachedFileSystemMetadata, result);
Assert.Equivalent(cachedFileSystemMetadata, secondResult);
}
+ ///
+ /// Tests that GetFilePaths returns only cached paths when clear is not called.
+ ///
[Fact]
public void GetFilePaths_GivenCachedFilePathWithoutClear_ReturnsOnlyCachedPaths()
{
const string path = "/music/someartist";
- var cachedPaths = new[]
- {
+ string[] cachedPaths =
+ [
"/music/someartist/song 1.mp3",
"/music/someartist/song 2.mp3",
"/music/someartist/song 3.mp3",
"/music/someartist/song 4.mp3",
- };
- var newPaths = new[]
- {
+ ];
+ string[] newPaths =
+ [
"/music/someartist/song 5.mp3",
"/music/someartist/song 6.mp3",
"/music/someartist/song 7.mp3",
"/music/someartist/song 8.mp3",
- };
+ ];
- var fileSystemMock = new Mock();
- fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths);
- var directoryService = new DirectoryService(fileSystemMock.Object);
+ Mock fileSystemMock = new();
+ _ = fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths);
+ DirectoryService directoryService = new(fileSystemMock.Object);
- var result = directoryService.GetFilePaths(path);
- fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths);
- var secondResult = directoryService.GetFilePaths(path);
+ IReadOnlyList result = directoryService.GetFilePaths(path);
+ _ = fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths);
+ IReadOnlyList secondResult = directoryService.GetFilePaths(path);
Assert.Equal(cachedPaths, result);
Assert.Equal(cachedPaths, secondResult);
}
+ ///
+ /// Tests that GetFilePaths returns new paths when clear is called.
+ ///
[Fact]
public void GetFilePaths_GivenCachedFilePathWithClear_ReturnsNewPaths()
{
const string path = "/music/someartist";
- var cachedPaths = new[]
- {
+ string[] cachedPaths =
+ [
"/music/someartist/song 1.mp3",
"/music/someartist/song 2.mp3",
"/music/someartist/song 3.mp3",
"/music/someartist/song 4.mp3",
- };
- var newPaths = new[]
- {
+ ];
+ string[] newPaths =
+ [
"/music/someartist/song 5.mp3",
"/music/someartist/song 6.mp3",
"/music/someartist/song 7.mp3",
"/music/someartist/song 8.mp3",
- };
+ ];
- var fileSystemMock = new Mock();
- fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths);
- var directoryService = new DirectoryService(fileSystemMock.Object);
+ Mock fileSystemMock = new();
+ _ = fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths);
+ DirectoryService directoryService = new(fileSystemMock.Object);
- var result = directoryService.GetFilePaths(path);
- fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths);
- var secondResult = directoryService.GetFilePaths(path, true);
+ IReadOnlyList result = directoryService.GetFilePaths(path);
+ _ = fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths);
+ IReadOnlyList secondResult = directoryService.GetFilePaths(path, true);
Assert.Equal(cachedPaths, result);
Assert.Equal(newPaths, secondResult);
diff --git a/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs b/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs
index 8cb83f17..9e530e79 100644
--- a/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs
+++ b/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs
@@ -2,49 +2,67 @@
// Copyright (c) PlaceholderCompany. All rights reserved.
//
-namespace Jellyfin.Controller.Tests.Entities;
-
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.MediaInfo;
-using Moq;
-using Xunit;
-
-public class BaseItemTests
+namespace Jellyfin.Controller.Tests.Entities
{
- [Theory]
- [InlineData("", "")]
- [InlineData("1", "0000000001")]
- [InlineData("t", "t")]
- [InlineData("test", "test")]
- [InlineData("test1", "test0000000001")]
- [InlineData("1test 2", "0000000001test 0000000002")]
- public void BaseItem_ModifySortChunks_Valid(string input, string expected)
- => Assert.Equal(expected, BaseItem.ModifySortChunks(input));
+ using MediaBrowser.Controller.Entities;
+ using MediaBrowser.Controller.Library;
+ using MediaBrowser.Model.MediaInfo;
+ using Moq;
+ using Xunit;
- [Theory]
- [InlineData("/Movies/Ted/Ted.mp4", "/Movies/Ted/Ted - Unrated Edition.mp4", "Ted", "Unrated Edition")]
- [InlineData("/Movies/Deadpool 2 (2018)/Deadpool 2 (2018).mkv", "/Movies/Deadpool 2 (2018)/Deadpool 2 (2018) - Super Duper Cut.mkv", "Deadpool 2 (2018)", "Super Duper Cut")]
- public void GetMediaSourceName_Valid(string primaryPath, string altPath, string name, string altName)
+ ///
+ /// Tests for .
+ ///
+ public class BaseItemTests
{
- var mediaSourceManager = new Mock();
- mediaSourceManager.Setup(x => x.GetPathProtocol(It.IsAny()))
- .Returns((string x) => MediaProtocol.File);
- BaseItem.MediaSourceManager = mediaSourceManager.Object;
-
- var video = new Video()
+ ///
+ /// Tests that ModifySortChunks correctly modifies sort chunks.
+ ///
+ /// The input string.
+ /// The expected output string.
+ [Theory]
+ [InlineData("", "")]
+ [InlineData("1", "0000000001")]
+ [InlineData("t", "t")]
+ [InlineData("test", "test")]
+ [InlineData("test1", "test0000000001")]
+ [InlineData("1test 2", "0000000001test 0000000002")]
+ public void BaseItem_ModifySortChunks_Valid(string input, string expected)
{
- Path = primaryPath
- };
+ Assert.Equal(expected, BaseItem.ModifySortChunks(input));
+ }
- var videoAlt = new Video()
+ ///
+ /// Tests that GetMediaSourceName returns the correct name for media sources.
+ ///
+ /// The primary path.
+ /// The alternate path.
+ /// The expected name for the primary path.
+ /// The expected name for the alternate path.
+ [Theory]
+ [InlineData("/Movies/Ted/Ted.mp4", "/Movies/Ted/Ted - Unrated Edition.mp4", "Ted", "Unrated Edition")]
+ [InlineData("/Movies/Deadpool 2 (2018)/Deadpool 2 (2018).mkv", "/Movies/Deadpool 2 (2018)/Deadpool 2 (2018) - Super Duper Cut.mkv", "Deadpool 2 (2018)", "Super Duper Cut")]
+ public void GetMediaSourceName_Valid(string primaryPath, string altPath, string name, string altName)
{
- Path = altPath,
- };
+ Mock mediaSourceManager = new();
+ _ = mediaSourceManager.Setup(x => x.GetPathProtocol(It.IsAny()))
+ .Returns((string x) => MediaProtocol.File);
+ BaseItem.MediaSourceManager = mediaSourceManager.Object;
- video.LocalAlternateVersions = [videoAlt.Path];
+ Video video = new()
+ {
+ Path = primaryPath,
+ };
- Assert.Equal(name, video.GetMediaSourceName(video));
- Assert.Equal(altName, video.GetMediaSourceName(videoAlt));
+ Video videoAlt = new()
+ {
+ Path = altPath,
+ };
+
+ video.LocalAlternateVersions = [videoAlt.Path];
+
+ Assert.Equal(name, video.GetMediaSourceName(video));
+ Assert.Equal(altName, video.GetMediaSourceName(videoAlt));
+ }
}
}
diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
index c81c0a04..ee30ed70 100644
--- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
+++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
@@ -4,6 +4,7 @@
{462584F7-5023-4019-9EAC-B98CA458C0A0}
net11.0
+ true
diff --git a/tests/Jellyfin.Controller.Tests/obj/project.nuget.cache b/tests/Jellyfin.Controller.Tests/obj/project.nuget.cache
index 6ab22ad8..53b06e0f 100644
--- a/tests/Jellyfin.Controller.Tests/obj/project.nuget.cache
+++ b/tests/Jellyfin.Controller.Tests/obj/project.nuget.cache
@@ -1,6 +1,6 @@
{
"version": 2,
- "dgSpecHash": "rCzbZx73oRU=",
+ "dgSpecHash": "GDKjP2XUxGM=",
"success": true,
"projectFilePath": "E:\\Projects\\pgsql-jellyfin\\tests\\Jellyfin.Controller.Tests\\Jellyfin.Controller.Tests.csproj",
"expectedPackageFiles": [
diff --git a/tests/Jellyfin.Extensions.Tests/CopyToExtensionsTests.cs b/tests/Jellyfin.Extensions.Tests/CopyToExtensionsTests.cs
index 28388a5d..ba098f84 100644
--- a/tests/Jellyfin.Extensions.Tests/CopyToExtensionsTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/CopyToExtensionsTests.cs
@@ -8,19 +8,33 @@ namespace Jellyfin.Extensions.Tests
using System.Collections.Generic;
using Xunit;
+ ///
+ /// Tests for CopyTo extension methods.
+ ///
public static class CopyToExtensionsTests
{
+ ///
+ /// Gets test data for valid CopyTo operations.
+ ///
+ /// The test data.
public static TheoryData, IList, int, IList> CopyTo_Valid_Correct_TestData()
{
- var data = new TheoryData, IList, int, IList>
+ TheoryData, IList, int, IList> data = new TheoryData, IList, int, IList>
{
{ new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, 0, new[] { 0, 1, 2, 3, 4, 5 } },
- { new[] { 0, 1, 2 }, new[] { 5, 4, 3, 2, 1, 0 }, 2, new[] { 5, 4, 0, 1, 2, 0 } }
+ { new[] { 0, 1, 2 }, new[] { 5, 4, 3, 2, 1, 0 }, 2, new[] { 5, 4, 0, 1, 2, 0 } },
};
return data;
}
+ ///
+ /// Tests that CopyTo correctly copies elements.
+ ///
+ /// The source list.
+ /// The destination list.
+ /// The starting index.
+ /// The expected result.
[Theory]
[MemberData(nameof(CopyTo_Valid_Correct_TestData))]
public static void CopyTo_Valid_Correct(IReadOnlyList source, IList destination, int index, IList expected)
@@ -29,20 +43,30 @@ namespace Jellyfin.Extensions.Tests
Assert.Equal(expected, destination);
}
+ ///
+ /// Gets test data for invalid CopyTo operations that should throw.
+ ///
+ /// The test data.
public static TheoryData, IList, int> CopyTo_Invalid_ThrowsArgumentOutOfRangeException_TestData()
{
- var data = new TheoryData, IList, int>
+ TheoryData, IList, int> data = new TheoryData, IList, int>
{
{ new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, -1 },
{ new[] { 0, 1, 2 }, new[] { 5, 4, 3, 2, 1, 0 }, 6 },
{ new[] { 0, 1, 2 }, Array.Empty(), 0 },
{ new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0 }, 0 },
- { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, 1 }
+ { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, 1 },
};
return data;
}
+ ///
+ /// Tests that CopyTo throws ArgumentOutOfRangeException for invalid inputs.
+ ///
+ /// The source list.
+ /// The destination list.
+ /// The starting index.
[Theory]
[MemberData(nameof(CopyTo_Invalid_ThrowsArgumentOutOfRangeException_TestData))]
public static void CopyTo_Invalid_ThrowsArgumentOutOfRangeException(IReadOnlyList source, IList destination, int index)
diff --git a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj
index a1fa817d..f41cfe03 100644
--- a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj
+++ b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj
@@ -2,6 +2,8 @@
net11.0
+ true
+ $(NoWarn);CS1591;CS1570;CS8600;SA1600;SA1309;SA1200
diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs
index ff39d866..ce9a2c84 100644
--- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs
@@ -11,16 +11,24 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
using Jellyfin.Extensions.Json.Converters;
using Xunit;
+ ///
+ /// Tests for the JsonBoolNumberConverter.
+ ///
public class JsonBoolNumberTests
{
- private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions()
+ private readonly JsonSerializerOptions _jsonOptions = new()
{
Converters =
{
- new JsonBoolNumberConverter()
- }
+ new JsonBoolNumberConverter(),
+ },
};
+ ///
+ /// Tests deserialization of numbers to boolean.
+ ///
+ /// The input string.
+ /// The expected output.
[Theory]
[InlineData("1", true)]
[InlineData("0", false)]
@@ -29,21 +37,33 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
[InlineData("false", false)]
public void Deserialize_Number_Valid_Success(string input, bool? output)
{
- var value = JsonSerializer.Deserialize(input, _jsonOptions);
+ bool value = JsonSerializer.Deserialize(input, this._jsonOptions);
Assert.Equal(value, output);
}
+ ///
+ /// Tests serialization of boolean values.
+ ///
+ /// The input boolean.
+ /// The expected output.
[Theory]
[InlineData(true, "true")]
[InlineData(false, "false")]
public void Serialize_Bool_Success(bool input, string output)
{
- var value = JsonSerializer.Serialize(input, _jsonOptions);
+ string value = JsonSerializer.Serialize(input, this._jsonOptions);
Assert.Equal(value, output);
}
+ ///
+ /// Property test that non-zero integers deserialize to true.
+ ///
+ /// The input non-zero integer.
+ /// A property test result.
[Property]
public Property Deserialize_NonZeroInt_True(NonZeroInt input)
- => JsonSerializer.Deserialize(input.ToString(), _jsonOptions).ToProperty();
+ {
+ return JsonSerializer.Deserialize(input.ToString(), this._jsonOptions).ToProperty();
+ }
}
}
diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolStringTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolStringTests.cs
index 918db3a1..861f6459 100644
--- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolStringTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolStringTests.cs
@@ -14,8 +14,8 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
{
Converters =
{
- new JsonBoolStringConverter()
- }
+ new JsonBoolStringConverter(),
+ },
};
[Theory]
@@ -23,7 +23,7 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
[InlineData(@"{ ""Value"": ""false"" }", false)]
public void Deserialize_String_Valid_Success(string input, bool output)
{
- var s = JsonSerializer.Deserialize(input, _jsonOptions);
+ TestStruct s = JsonSerializer.Deserialize(input, this._jsonOptions);
Assert.Equal(s.Value, output);
}
@@ -32,7 +32,7 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
[InlineData(false, "false")]
public void Serialize_Bool_Success(bool input, string output)
{
- var value = JsonSerializer.Serialize(input, _jsonOptions);
+ string value = JsonSerializer.Serialize(input, this._jsonOptions);
Assert.Equal(value, output);
}
diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedCollectionTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedCollectionTests.cs
index 4b2b2e7d..c8a43402 100644
--- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedCollectionTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedCollectionTests.cs
@@ -7,205 +7,255 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
- using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Jellyfin.Extensions.Tests.Json.Models;
using MediaBrowser.Model.Session;
using Xunit;
+ ///
+ /// Tests for JSON comma delimited collection converter.
+ ///
public class JsonCommaDelimitedCollectionTests
{
- private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions()
+ private readonly JsonSerializerOptions jsonOptions = new()
{
Converters =
{
- new JsonStringEnumConverter()
- }
+ new JsonStringEnumConverter(),
+ },
};
+ ///
+ /// Tests that deserializing null string value succeeds.
+ ///
[Fact]
public void Deserialize_String_Null_Success()
{
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": null }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": null }", this.jsonOptions);
Assert.Null(value?.Value);
}
+ ///
+ /// Tests that deserializing empty string succeeds.
+ ///
[Fact]
public void Deserialize_Empty_Success()
{
- var desiredValue = new GenericBodyArrayModel
+ GenericBodyArrayModel desiredValue = new()
{
- Value = Array.Empty()
+ Value = [],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": """" }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": """" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing empty string to list throws exception.
+ ///
[Fact]
public void Deserialize_EmptyList_Success()
{
- var desiredValue = new GenericBodyListModel
+ GenericBodyListModel desiredValue = new()
{
- Value = []
+ Value = [],
};
- Assert.Throws(() => JsonSerializer.Deserialize>(@"{ ""Value"": """" }", _jsonOptions));
+ _ = Assert.Throws(() => JsonSerializer.Deserialize>(@"{ ""Value"": """" }", this.jsonOptions));
}
+ ///
+ /// Tests that deserializing empty string to IReadOnlyList succeeds.
+ ///
[Fact]
public void Deserialize_EmptyIReadOnlyList_Success()
{
- var desiredValue = new GenericBodyIReadOnlyListModel
+ GenericBodyIReadOnlyListModel desiredValue = new()
{
- Value = []
+ Value = [],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": """" }", _jsonOptions);
+ GenericBodyIReadOnlyListModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": """" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing comma-delimited string succeeds.
+ ///
[Fact]
public void Deserialize_String_Valid_Success()
{
- var desiredValue = new GenericBodyArrayModel
+ GenericBodyArrayModel desiredValue = new()
{
- Value = ["a", "b", "c"]
+ Value = ["a", "b", "c"],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""a,b,c"" }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""a,b,c"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing comma-delimited string to list throws exception.
+ ///
[Fact]
public void Deserialize_StringList_Valid_Success()
{
- var desiredValue = new GenericBodyListModel
+ GenericBodyListModel desiredValue = new()
{
- Value = ["a", "b", "c"]
+ Value = ["a", "b", "c"],
};
- Assert.Throws(() => JsonSerializer.Deserialize>(@"{ ""Value"": ""a,b,c"" }", _jsonOptions));
+ _ = Assert.Throws(() => JsonSerializer.Deserialize>(@"{ ""Value"": ""a,b,c"" }", this.jsonOptions));
}
+ ///
+ /// Tests that deserializing comma-delimited string with spaces succeeds.
+ ///
[Fact]
public void Deserialize_String_Space_Valid_Success()
{
- var desiredValue = new GenericBodyArrayModel
+ GenericBodyArrayModel desiredValue = new()
{
- Value = ["a", "b", "c"]
+ Value = ["a", "b", "c"],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""a, b, c"" }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""a, b, c"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing comma-delimited enum string succeeds.
+ ///
[Fact]
public void Deserialize_GenericCommandType_Valid_Success()
{
- var desiredValue = new GenericBodyArrayModel
+ GenericBodyArrayModel desiredValue = new()
{
- Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown]
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp,MoveDown"" }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp,MoveDown"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing comma-delimited enum string with empty entry succeeds.
+ ///
[Fact]
public void Deserialize_GenericCommandType_EmptyEntry_Success()
{
- var desiredValue = new GenericBodyArrayModel
+ GenericBodyArrayModel desiredValue = new()
{
- Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown]
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp,,MoveDown"" }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp,,MoveDown"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing comma-delimited enum string with invalid value succeeds.
+ ///
[Fact]
public void Deserialize_GenericCommandType_Invalid_Success()
{
- var desiredValue = new GenericBodyArrayModel
+ GenericBodyArrayModel desiredValue = new()
{
- Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown]
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp,TotallyNotAValidCommand,MoveDown"" }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp,TotallyNotAValidCommand,MoveDown"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing comma-delimited enum string with spaces succeeds.
+ ///
[Fact]
public void Deserialize_GenericCommandType_Space_Valid_Success()
{
- var desiredValue = new GenericBodyArrayModel
+ GenericBodyArrayModel desiredValue = new()
{
- Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown]
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp, MoveDown"" }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp, MoveDown"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing JSON array of strings succeeds.
+ ///
[Fact]
public void Deserialize_String_Array_Valid_Success()
{
- var desiredValue = new GenericBodyArrayModel
+ GenericBodyArrayModel desiredValue = new()
{
- Value = ["a", "b", "c"]
+ Value = ["a", "b", "c"],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": [""a"",""b"",""c""] }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": [""a"",""b"",""c""] }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing JSON array of enums succeeds.
+ ///
[Fact]
public void Deserialize_GenericCommandType_Array_Valid_Success()
{
- var desiredValue = new GenericBodyArrayModel
+ GenericBodyArrayModel desiredValue = new()
{
- Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown]
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", _jsonOptions);
+ GenericBodyArrayModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that serializing readonly collection succeeds.
+ ///
[Fact]
public void Serialize_GenericCommandType_ReadOnlyArray_Valid_Success()
{
- var valueToSerialize = new GenericBodyIReadOnlyCollectionModel
+ GenericBodyIReadOnlyCollectionModel valueToSerialize = new()
{
- Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }.AsReadOnly()
+ Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }.AsReadOnly(),
};
- string value = JsonSerializer.Serialize>(valueToSerialize, _jsonOptions);
+ string value = JsonSerializer.Serialize>(valueToSerialize, this.jsonOptions);
Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value);
}
+ ///
+ /// Tests that serializing immutable array succeeds.
+ ///
[Fact]
public void Serialize_GenericCommandType_ImmutableArrayArray_Valid_Success()
{
- var valueToSerialize = new GenericBodyIReadOnlyCollectionModel
+ GenericBodyIReadOnlyCollectionModel valueToSerialize = new()
{
- Value = ImmutableArray.Create(new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown })
+ Value = ImmutableArray.Create([GeneralCommandType.MoveUp, GeneralCommandType.MoveDown]),
};
- string value = JsonSerializer.Serialize>(valueToSerialize, _jsonOptions);
+ string value = JsonSerializer.Serialize>(valueToSerialize, this.jsonOptions);
Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value);
}
+ ///
+ /// Tests that serializing list succeeds.
+ ///
[Fact]
public void Serialize_GenericCommandType_List_Valid_Success()
{
- var valueToSerialize = new GenericBodyIReadOnlyListModel
+ GenericBodyIReadOnlyListModel valueToSerialize = new()
{
- Value = new List { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- string value = JsonSerializer.Serialize>(valueToSerialize, _jsonOptions);
+ string value = JsonSerializer.Serialize>(valueToSerialize, this.jsonOptions);
Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value);
}
}
diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs
index 69f9dded..6e32f867 100644
--- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs
@@ -4,104 +4,127 @@
namespace Jellyfin.Extensions.Tests.Json.Converters
{
- using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using Jellyfin.Extensions.Tests.Json.Models;
using MediaBrowser.Model.Session;
using Xunit;
+ ///
+ /// Tests for JSON comma delimited IReadOnlyList converter.
+ ///
public class JsonCommaDelimitedIReadOnlyListTests
{
- private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions()
+ private readonly JsonSerializerOptions jsonOptions = new()
{
Converters =
{
- new JsonStringEnumConverter()
- }
+ new JsonStringEnumConverter(),
+ },
};
+ ///
+ /// Tests that deserializing comma-delimited string succeeds.
+ ///
[Fact]
public void Deserialize_String_Valid_Success()
{
- var desiredValue = new GenericBodyIReadOnlyListModel
+ GenericBodyIReadOnlyListModel desiredValue = new()
{
- Value = new[] { "a", "b", "c" }
+ Value = ["a", "b", "c"],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""a,b,c"" }", _jsonOptions);
+ GenericBodyIReadOnlyListModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""a,b,c"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing comma-delimited string with spaces succeeds.
+ ///
[Fact]
public void Deserialize_String_Space_Valid_Success()
{
- var desiredValue = new GenericBodyIReadOnlyListModel
+ GenericBodyIReadOnlyListModel desiredValue = new()
{
- Value = new[] { "a", "b", "c" }
+ Value = ["a", "b", "c"],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""a, b, c"" }", _jsonOptions);
+ GenericBodyIReadOnlyListModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""a, b, c"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing comma-delimited enum string succeeds.
+ ///
[Fact]
public void Deserialize_GenericCommandType_Valid_Success()
{
- var desiredValue = new GenericBodyIReadOnlyListModel
+ GenericBodyIReadOnlyListModel desiredValue = new()
{
- Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp,MoveDown"" }", _jsonOptions);
+ GenericBodyIReadOnlyListModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp,MoveDown"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing comma-delimited enum string with spaces succeeds.
+ ///
[Fact]
public void Deserialize_GenericCommandType_Space_Valid_Success()
{
- var desiredValue = new GenericBodyIReadOnlyListModel
+ GenericBodyIReadOnlyListModel desiredValue = new()
{
- Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp, MoveDown"" }", _jsonOptions);
+ GenericBodyIReadOnlyListModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": ""MoveUp, MoveDown"" }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing JSON array of strings succeeds.
+ ///
[Fact]
public void Deserialize_String_Array_Valid_Success()
{
- var desiredValue = new GenericBodyIReadOnlyListModel
+ GenericBodyIReadOnlyListModel desiredValue = new()
{
- Value = new[] { "a", "b", "c" }
+ Value = ["a", "b", "c"],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": [""a"",""b"",""c""] }", _jsonOptions);
+ GenericBodyIReadOnlyListModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": [""a"",""b"",""c""] }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that deserializing JSON array of enums succeeds.
+ ///
[Fact]
public void Deserialize_GenericCommandType_Array_Valid_Success()
{
- var desiredValue = new GenericBodyIReadOnlyListModel
+ GenericBodyIReadOnlyListModel desiredValue = new()
{
- Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- var value = JsonSerializer.Deserialize>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", _jsonOptions);
+ GenericBodyIReadOnlyListModel? value = JsonSerializer.Deserialize>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", this.jsonOptions);
Assert.Equal(desiredValue.Value, value?.Value);
}
+ ///
+ /// Tests that serializing IReadOnlyList succeeds.
+ ///
[Fact]
public void Serialize_GenericCommandType_IReadOnlyList_Valid_Success()
{
- var valueToSerialize = new GenericBodyIReadOnlyListModel
+ GenericBodyIReadOnlyListModel valueToSerialize = new()
{
- Value = new List { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
+ Value = [GeneralCommandType.MoveUp, GeneralCommandType.MoveDown],
};
- string value = JsonSerializer.Serialize>(valueToSerialize, _jsonOptions);
+ string value = JsonSerializer.Serialize>(valueToSerialize, this.jsonOptions);
Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value);
}
}
diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonDefaultStringEnumConverterTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonDefaultStringEnumConverterTests.cs
index 1cfd8825..140a6e2f 100644
--- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonDefaultStringEnumConverterTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonDefaultStringEnumConverterTests.cs
@@ -2,115 +2,116 @@
// Copyright (c) PlaceholderCompany. All rights reserved.
//
-namespace Jellyfin.Extensions.Tests.Json.Converters;
-
-using System.Text.Json;
-using Jellyfin.Data.Enums;
-using Jellyfin.Extensions.Json.Converters;
-using Xunit;
-
-public class JsonDefaultStringEnumConverterTests
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
- private readonly JsonSerializerOptions _jsonOptions = new() { Converters = { new JsonDefaultStringEnumConverterFactory() } };
+ using System.Text.Json;
+ using Jellyfin.Data.Enums;
+ using Jellyfin.Extensions.Json.Converters;
+ using Xunit;
- ///
- /// Test to ensure that `null` and empty string are deserialized to the default value.
- ///
- /// The input string.
- /// The expected enum value.
- [Theory]
- [InlineData("\"\"", MediaStreamProtocol.http)]
- [InlineData("\"Http\"", MediaStreamProtocol.http)]
- [InlineData("\"Hls\"", MediaStreamProtocol.hls)]
- public void Deserialize_Enum_Direct(string input, MediaStreamProtocol output)
+ public class JsonDefaultStringEnumConverterTests
{
- var value = JsonSerializer.Deserialize(input, _jsonOptions);
- Assert.Equal(output, value);
- }
+ private readonly JsonSerializerOptions _jsonOptions = new() { Converters = { new JsonDefaultStringEnumConverterFactory() } };
- ///
- /// Test to ensure that `null` and empty string are deserialized to the default value.
- ///
- /// The input string.
- /// The expected enum value.
- [Theory]
- [InlineData(null, MediaStreamProtocol.http)]
- [InlineData("\"\"", MediaStreamProtocol.http)]
- [InlineData("\"Http\"", MediaStreamProtocol.http)]
- [InlineData("\"Hls\"", MediaStreamProtocol.hls)]
- public void Deserialize_Enum(string? input, MediaStreamProtocol output)
- {
- input ??= "null";
- var json = $"{{ \"EnumValue\": {input} }}";
- var value = JsonSerializer.Deserialize(json, _jsonOptions);
- Assert.NotNull(value);
- Assert.Equal(output, value.EnumValue);
- }
+ ///
+ /// Test to ensure that `null` and empty string are deserialized to the default value.
+ ///
+ /// The input string.
+ /// The expected enum value.
+ [Theory]
+ [InlineData("\"\"", MediaStreamProtocol.http)]
+ [InlineData("\"Http\"", MediaStreamProtocol.http)]
+ [InlineData("\"Hls\"", MediaStreamProtocol.hls)]
+ public void Deserialize_Enum_Direct(string input, MediaStreamProtocol output)
+ {
+ MediaStreamProtocol value = JsonSerializer.Deserialize(input, this._jsonOptions);
+ Assert.Equal(output, value);
+ }
- ///
- /// Test to ensure that empty string is deserialized to the default value,
- /// and `null` is deserialized to `null`.
- ///
- /// The input string.
- /// The expected enum value.
- [Theory]
- [InlineData(null, null)]
- [InlineData("\"\"", MediaStreamProtocol.http)]
- [InlineData("\"Http\"", MediaStreamProtocol.http)]
- [InlineData("\"Hls\"", MediaStreamProtocol.hls)]
- public void Deserialize_Enum_Nullable(string? input, MediaStreamProtocol? output)
- {
- input ??= "null";
- var json = $"{{ \"EnumValue\": {input} }}";
- var value = JsonSerializer.Deserialize(json, _jsonOptions);
- Assert.NotNull(value);
- Assert.Equal(output, value.EnumValue);
- }
+ ///
+ /// Test to ensure that `null` and empty string are deserialized to the default value.
+ ///
+ /// The input string.
+ /// The expected enum value.
+ [Theory]
+ [InlineData(null, MediaStreamProtocol.http)]
+ [InlineData("\"\"", MediaStreamProtocol.http)]
+ [InlineData("\"Http\"", MediaStreamProtocol.http)]
+ [InlineData("\"Hls\"", MediaStreamProtocol.hls)]
+ public void Deserialize_Enum(string? input, MediaStreamProtocol output)
+ {
+ input ??= "null";
+ string json = $"{{ \"EnumValue\": {input} }}";
+ TestClass value = JsonSerializer.Deserialize(json, this._jsonOptions);
+ Assert.NotNull(value);
+ Assert.Equal(output, value.EnumValue);
+ }
- ///
- /// Ensures that the roundtrip serialization & deserialization is successful.
- ///
- /// Input enum.
- /// Output enum.
- [Theory]
- [InlineData(MediaStreamProtocol.http, MediaStreamProtocol.http)]
- [InlineData(MediaStreamProtocol.hls, MediaStreamProtocol.hls)]
- public void Enum_RoundTrip(MediaStreamProtocol input, MediaStreamProtocol output)
- {
- var inputObj = new TestClass { EnumValue = input };
+ ///
+ /// Test to ensure that empty string is deserialized to the default value,
+ /// and `null` is deserialized to `null`.
+ ///
+ /// The input string.
+ /// The expected enum value.
+ [Theory]
+ [InlineData(null, null)]
+ [InlineData("\"\"", MediaStreamProtocol.http)]
+ [InlineData("\"Http\"", MediaStreamProtocol.http)]
+ [InlineData("\"Hls\"", MediaStreamProtocol.hls)]
+ public void Deserialize_Enum_Nullable(string? input, MediaStreamProtocol? output)
+ {
+ input ??= "null";
+ string json = $"{{ \"EnumValue\": {input} }}";
+ NullTestClass value = JsonSerializer.Deserialize(json, this._jsonOptions);
+ Assert.NotNull(value);
+ Assert.Equal(output, value.EnumValue);
+ }
- var outputObj = JsonSerializer.Deserialize(JsonSerializer.Serialize(inputObj, _jsonOptions), _jsonOptions);
+ ///
+ /// Ensures that the roundtrip serialization & deserialization is successful.
+ ///
+ /// Input enum.
+ /// Output enum.
+ [Theory]
+ [InlineData(MediaStreamProtocol.http, MediaStreamProtocol.http)]
+ [InlineData(MediaStreamProtocol.hls, MediaStreamProtocol.hls)]
+ public void Enum_RoundTrip(MediaStreamProtocol input, MediaStreamProtocol output)
+ {
+ TestClass inputObj = new() { EnumValue = input };
- Assert.NotNull(outputObj);
- Assert.Equal(output, outputObj.EnumValue);
- }
+ TestClass? outputObj = JsonSerializer.Deserialize(JsonSerializer.Serialize(inputObj, this._jsonOptions), this._jsonOptions);
- ///
- /// Ensures that the roundtrip serialization & deserialization is successful, including null.
- ///
- /// Input enum.
- /// Output enum.
- [Theory]
- [InlineData(MediaStreamProtocol.http, MediaStreamProtocol.http)]
- [InlineData(MediaStreamProtocol.hls, MediaStreamProtocol.hls)]
- [InlineData(null, null)]
- public void Enum_RoundTrip_Nullable(MediaStreamProtocol? input, MediaStreamProtocol? output)
- {
- var inputObj = new NullTestClass { EnumValue = input };
+ Assert.NotNull(outputObj);
+ Assert.Equal(output, outputObj.EnumValue);
+ }
- var outputObj = JsonSerializer.Deserialize(JsonSerializer.Serialize(inputObj, _jsonOptions), _jsonOptions);
+ ///
+ /// Ensures that the roundtrip serialization & deserialization is successful, including null.
+ ///
+ /// Input enum.
+ /// Output enum.
+ [Theory]
+ [InlineData(MediaStreamProtocol.http, MediaStreamProtocol.http)]
+ [InlineData(MediaStreamProtocol.hls, MediaStreamProtocol.hls)]
+ [InlineData(null, null)]
+ public void Enum_RoundTrip_Nullable(MediaStreamProtocol? input, MediaStreamProtocol? output)
+ {
+ NullTestClass inputObj = new() { EnumValue = input };
- Assert.NotNull(outputObj);
- Assert.Equal(output, outputObj.EnumValue);
- }
+ NullTestClass? outputObj = JsonSerializer.Deserialize(JsonSerializer.Serialize(inputObj, this._jsonOptions), this._jsonOptions);
- private sealed class TestClass
- {
- public MediaStreamProtocol EnumValue { get; set; }
- }
+ Assert.NotNull(outputObj);
+ Assert.Equal(output, outputObj.EnumValue);
+ }
- private sealed class NullTestClass
- {
- public MediaStreamProtocol? EnumValue { get; set; }
+ private sealed class TestClass
+ {
+ public MediaStreamProtocol EnumValue { get; set; }
+ }
+
+ private sealed class NullTestClass
+ {
+ public MediaStreamProtocol? EnumValue { get; set; }
+ }
}
}
diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonFlagEnumTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonFlagEnumTests.cs
index df54a73b..4ada0f44 100644
--- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonFlagEnumTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonFlagEnumTests.cs
@@ -2,31 +2,32 @@
// Copyright (c) PlaceholderCompany. All rights reserved.
//
-namespace Jellyfin.Extensions.Tests.Json.Converters;
-
-using System.Text.Json;
-using Jellyfin.Extensions.Json.Converters;
-using MediaBrowser.Model.Session;
-using Xunit;
-
-public class JsonFlagEnumTests
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
- private readonly JsonSerializerOptions _jsonOptions = new()
+ using System.Text.Json;
+ using Jellyfin.Extensions.Json.Converters;
+ using MediaBrowser.Model.Session;
+ using Xunit;
+
+ public class JsonFlagEnumTests
{
- Converters =
+ private readonly JsonSerializerOptions _jsonOptions = new()
{
- new JsonFlagEnumConverter()
+ Converters =
+ {
+ new JsonFlagEnumConverter(),
+ },
+ };
+
+ [Theory]
+ [InlineData(TranscodeReason.AudioIsExternal | TranscodeReason.ContainerNotSupported, "[\"ContainerNotSupported\",\"AudioIsExternal\"]")]
+ [InlineData(TranscodeReason.AudioIsExternal | TranscodeReason.ContainerNotSupported | TranscodeReason.VideoBitDepthNotSupported, "[\"ContainerNotSupported\",\"AudioIsExternal\",\"VideoBitDepthNotSupported\"]")]
+ [InlineData((TranscodeReason)0, "[]")]
+ public void Serialize_Transcode_Reason(TranscodeReason transcodeReason, string output)
+ {
+ string result = JsonSerializer.Serialize(transcodeReason, this._jsonOptions);
+
+ Assert.Equal(output, result);
}
- };
-
- [Theory]
- [InlineData(TranscodeReason.AudioIsExternal | TranscodeReason.ContainerNotSupported, "[\"ContainerNotSupported\",\"AudioIsExternal\"]")]
- [InlineData(TranscodeReason.AudioIsExternal | TranscodeReason.ContainerNotSupported | TranscodeReason.VideoBitDepthNotSupported, "[\"ContainerNotSupported\",\"AudioIsExternal\",\"VideoBitDepthNotSupported\"]")]
- [InlineData((TranscodeReason)0, "[]")]
- public void Serialize_Transcode_Reason(TranscodeReason transcodeReason, string output)
- {
- var result = JsonSerializer.Serialize(transcodeReason, _jsonOptions);
-
- Assert.Equal(output, result);
}
}
diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonGuidConverterTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonGuidConverterTests.cs
index 8b0b21bf..a88a4b1a 100644
--- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonGuidConverterTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonGuidConverterTests.cs
@@ -15,49 +15,49 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
public JsonGuidConverterTests()
{
- _options = new JsonSerializerOptions();
- _options.Converters.Add(new JsonGuidConverter());
+ this._options = new JsonSerializerOptions();
+ this._options.Converters.Add(new JsonGuidConverter());
}
[Fact]
public void Deserialize_Valid_Success()
{
- Guid value = JsonSerializer.Deserialize(@"""a852a27afe324084ae66db579ee3ee18""", _options);
- Assert.Equal(new Guid("a852a27afe324084ae66db579ee3ee18"), value);
+ Guid value = JsonSerializer.Deserialize(@"""a852a27afe324084ae66db579ee3ee18""", this._options);
+ Assert.Equal(new("a852a27afe324084ae66db579ee3ee18"), value);
}
[Fact]
public void Deserialize_ValidDashed_Success()
{
- Guid value = JsonSerializer.Deserialize(@"""e9b2dcaa-529c-426e-9433-5e9981f27f2e""", _options);
- Assert.Equal(new Guid("e9b2dcaa-529c-426e-9433-5e9981f27f2e"), value);
+ Guid value = JsonSerializer.Deserialize