aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Barron <barronpm@gmail.com>2021-06-22 21:09:54 -0400
committerPatrick Barron <barronpm@gmail.com>2021-06-23 20:22:12 -0400
commitae878fa051e73dd1df90f1fed3ca5f7ad28b7beb (patch)
tree8d590d6ae9aea9a84626fa31695f0ed47969e33d
parentf96722fa749b94b8affbf75da5d6941cab219a84 (diff)
parent94056049131a8573d7a4d0690da04c0e8bc240ad (diff)
Merge branch 'master' into authenticationdb-efcore
# Conflicts: # Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs # Emby.Server.Implementations/Session/SessionManager.cs # Jellyfin.Server.Implementations/Security/AuthorizationContext.cs
-rw-r--r--.github/workflows/automation.yml2
-rw-r--r--Emby.Dlna/DlnaManager.cs2
-rw-r--r--Emby.Dlna/Service/BaseControlHandler.cs2
-rw-r--r--Emby.Naming/Audio/AudioFileParser.cs2
-rw-r--r--Emby.Naming/Video/VideoResolver.cs2
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs2
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs4
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketConnection.cs2
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs2
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs1
-rw-r--r--Emby.Server.Implementations/Library/LiveStreamHelper.cs2
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/SearchEngine.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs1
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs4
-rw-r--r--Emby.Server.Implementations/Plugins/PluginManager.cs4
-rw-r--r--Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs177
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs2
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs5
-rw-r--r--Emby.Server.Implementations/Sorting/StudioComparer.cs3
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs2
-rw-r--r--Jellyfin.Api/BaseJellyfinApiController.cs2
-rw-r--r--Jellyfin.Api/Controllers/ConfigurationController.cs2
-rw-r--r--Jellyfin.Api/Controllers/PluginsController.cs2
-rw-r--r--Jellyfin.Api/Controllers/QuickConnectController.cs82
-rw-r--r--Jellyfin.Api/Controllers/TvShowsController.cs2
-rw-r--r--Jellyfin.Api/Controllers/UserLibraryController.cs2
-rw-r--r--Jellyfin.Api/Extensions/DtoExtensions.cs2
-rw-r--r--Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs2
-rw-r--r--Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs2
-rw-r--r--Jellyfin.Api/Models/SessionDtos/ClientCapabilitiesDto.cs4
-rw-r--r--Jellyfin.Drawing.Skia/SkiaEncoder.cs7
-rw-r--r--Jellyfin.Server.Implementations/Security/AuthorizationContext.cs2
-rw-r--r--Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs2
-rw-r--r--Jellyfin.Server/Formatters/CamelCaseJsonProfileFormatter.cs2
-rw-r--r--Jellyfin.Server/Formatters/PascalCaseJsonProfileFormatter.cs2
-rw-r--r--Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs2
-rw-r--r--Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs2
-rw-r--r--Jellyfin.sln16
-rw-r--r--MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs3
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Extensions.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Person.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs2
-rw-r--r--MediaBrowser.Controller/Extensions/StringExtensions.cs73
-rw-r--r--MediaBrowser.Controller/Library/NameExtensions.cs1
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Controller/QuickConnect/IQuickConnect.cs66
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs5
-rw-r--r--MediaBrowser.Controller/Sorting/SortExtensions.cs5
-rw-r--r--MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs2
-rw-r--r--MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs11
-rw-r--r--MediaBrowser.Model/Entities/VirtualFolderInfo.cs1
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj3
-rw-r--r--MediaBrowser.Model/QuickConnect/QuickConnectResult.cs32
-rw-r--r--MediaBrowser.Model/QuickConnect/QuickConnectState.cs23
-rw-r--r--MediaBrowser.Providers/Manager/ProviderUtils.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs14
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableInt32Converter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableInt32Converter.cs)6
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableStringConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs)6
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs4
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs4
-rw-r--r--MediaBrowser.Providers/Properties/AssemblyInfo.cs2
-rw-r--r--MediaBrowser.Providers/Studios/StudiosImageProvider.cs2
-rwxr-xr-xdebian/rules2
-rw-r--r--src/Jellyfin.Extensions/AlphanumericComparator.cs (renamed from MediaBrowser.Controller/Sorting/AlphanumComparator.cs)15
-rw-r--r--src/Jellyfin.Extensions/CopyToExtensions.cs (renamed from MediaBrowser.Common/Extensions/CopyToExtensions.cs)2
-rw-r--r--src/Jellyfin.Extensions/EnumerableExtensions.cs (renamed from MediaBrowser.Common/Extensions/EnumerableExtensions.cs)4
-rw-r--r--src/Jellyfin.Extensions/Jellyfin.Extensions.csproj30
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonBoolNumberConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonBoolNumberConverter.cs)4
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverter.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs (renamed from MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonDateTimeConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonDateTimeConverter.cs)4
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonDelimitedArrayConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonDelimitedArrayConverter.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonGuidConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonGuidConverter.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonLowerCaseConverter.cs (renamed from MediaBrowser.Model/Entities/JsonLowerCaseConverter.cs)10
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonNullableGuidConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonNullableGuidConverter.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonNullableStructConverter.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverterFactory.cs (renamed from MediaBrowser.Common/Json/Converters/JsonNullableStructConverterFactory.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverter.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs (renamed from MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonStringConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonStringConverter.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonVersionConverter.cs (renamed from MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs)2
-rw-r--r--src/Jellyfin.Extensions/Json/JsonDefaults.cs (renamed from MediaBrowser.Common/Json/JsonDefaults.cs)4
-rw-r--r--src/Jellyfin.Extensions/ShuffleExtensions.cs (renamed from MediaBrowser.Common/Extensions/ShuffleExtensions.cs)2
-rw-r--r--src/Jellyfin.Extensions/SplitStringExtensions.cs (renamed from MediaBrowser.Common/Extensions/SplitStringExtensions.cs)38
-rw-r--r--src/Jellyfin.Extensions/StreamExtensions.cs (renamed from MediaBrowser.Common/Extensions/StreamExtensions.cs)2
-rw-r--r--src/Jellyfin.Extensions/StringBuilderExtensions.cs (renamed from MediaBrowser.Common/Extensions/StringBuilderExtensions.cs)4
-rw-r--r--src/Jellyfin.Extensions/StringExtensions.cs31
-rw-r--r--tests/Jellyfin.Extensions.Tests/AlphanumericComparatorTests.cs (renamed from tests/Jellyfin.Controller.Tests/AlphanumComparatorTests.cs)9
-rw-r--r--tests/Jellyfin.Extensions.Tests/CopyToExtensionsTests.cs (renamed from tests/Jellyfin.Common.Tests/Extensions/CopyToExtensionsTests.cs)3
-rw-r--r--tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj38
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs (renamed from tests/Jellyfin.Common.Tests/Json/JsonBoolNumberTests.cs)6
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedArrayTests.cs (renamed from tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs)6
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs (renamed from tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedIReadOnlyListTests.cs)6
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Converters/JsonGuidConverterTests.cs (renamed from tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs)4
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Converters/JsonLowerCaseConverterTests.cs (renamed from tests/Jellyfin.Model.Tests/Entities/JsonLowerCaseConverterTests.cs)3
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Converters/JsonNullableGuidConverterTests.cs (renamed from tests/Jellyfin.Common.Tests/Json/JsonNullableGuidConverterTests.cs)4
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Converters/JsonStringConverterTests.cs (renamed from tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs)6
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Converters/JsonVersionConverterTests.cs (renamed from tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs)6
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyArrayModel.cs (renamed from tests/Jellyfin.Common.Tests/Models/GenericBodyArrayModel.cs)6
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyListModel.cs (renamed from tests/Jellyfin.Common.Tests/Models/GenericBodyIReadOnlyListModel.cs)6
-rw-r--r--tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs (renamed from tests/Jellyfin.Common.Tests/Extensions/ShuffleExtensionsTests.cs)3
-rw-r--r--tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs (renamed from tests/Jellyfin.Controller.Tests/Extensions/StringExtensionsTests.cs)3
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs2
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs2
-rw-r--r--tests/Jellyfin.Providers.Tests/Omdb/JsonOmdbConverterTests.cs (renamed from tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs)3
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs2
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs2
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs2
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs2
126 files changed, 428 insertions, 539 deletions
diff --git a/.github/workflows/automation.yml b/.github/workflows/automation.yml
index 8da2349c8..38415f1c6 100644
--- a/.github/workflows/automation.yml
+++ b/.github/workflows/automation.yml
@@ -11,6 +11,7 @@ jobs:
label:
name: Labeling
runs-on: ubuntu-latest
+ if: ${{ github.repository == 'jellyfin/jellyfin' }}
steps:
- name: Apply label
uses: eps1lon/actions-label-merge-conflict@v2.0.1
@@ -22,6 +23,7 @@ jobs:
project:
name: Project board
runs-on: ubuntu-latest
+ if: ${{ github.repository == 'jellyfin/jellyfin' }}
steps:
- name: Remove from 'Current Release' project
uses: alex-page/github-project-automation-plus@v0.7.1
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index a1b106704..b08f7590d 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -14,9 +14,9 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Emby.Dlna.Profiles;
using Emby.Dlna.Server;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs
index 904c23d99..b3ee860f4 100644
--- a/Emby.Dlna/Service/BaseControlHandler.cs
+++ b/Emby.Dlna/Service/BaseControlHandler.cs
@@ -6,9 +6,9 @@ using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
+using Diacritics.Extensions;
using Emby.Dlna.Didl;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Extensions;
using Microsoft.Extensions.Logging;
namespace Emby.Dlna.Service
diff --git a/Emby.Naming/Audio/AudioFileParser.cs b/Emby.Naming/Audio/AudioFileParser.cs
index af4aa0059..2b610ec79 100644
--- a/Emby.Naming/Audio/AudioFileParser.cs
+++ b/Emby.Naming/Audio/AudioFileParser.cs
@@ -1,7 +1,7 @@
using System;
using System.IO;
using Emby.Naming.Common;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
namespace Emby.Naming.Audio
{
diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs
index c4ac5fdc6..3b1d906c6 100644
--- a/Emby.Naming/Video/VideoResolver.cs
+++ b/Emby.Naming/Video/VideoResolver.cs
@@ -2,7 +2,7 @@ using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Emby.Naming.Common;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
namespace Emby.Naming.Video
{
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index 448f12403..093607dd5 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -11,7 +11,7 @@ using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 9b147b5d7..2cb10765f 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -11,10 +11,12 @@ using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading;
+using Diacritics.Extensions;
using Emby.Server.Implementations.Playlists;
using Jellyfin.Data.Enums;
+using Jellyfin.Extensions;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
index 8f7d60669..5d38ea0ca 100644
--- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
+++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
@@ -7,7 +7,7 @@ using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 64d802457..ca028a3ca 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -6,8 +6,8 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
+using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 028673529..d80637332 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -21,6 +21,7 @@ using Emby.Server.Implementations.Playlists;
using Emby.Server.Implementations.ScheduledTasks;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller;
diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs
index 4ef7923db..806269182 100644
--- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs
+++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs
@@ -12,7 +12,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index b812b6b61..91c9e61cf 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -15,7 +15,7 @@ using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 97f96f746..889e29a6b 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -6,7 +6,7 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Emby.Naming.Video;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs
index 26e615fa0..9d0a24a88 100644
--- a/Emby.Server.Implementations/Library/SearchEngine.cs
+++ b/Emby.Server.Implementations/Library/SearchEngine.cs
@@ -5,12 +5,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Diacritics.Extensions;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Search;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 26e4ef1ed..93781cb7b 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -11,9 +11,9 @@ using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Extensions;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index bdab8c3e4..4a031e475 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -7,7 +7,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index bd4b5639c..b7639a51c 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -15,7 +15,7 @@ using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Cryptography;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 54de841fe..011748d1d 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -12,8 +12,9 @@ using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Extensions;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 40a162890..c9657f605 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -10,6 +10,7 @@ using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs
index b1ff28c2c..a9e3bfdb0 100644
--- a/Emby.Server.Implementations/Localization/LocalizationManager.cs
+++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs
@@ -8,8 +8,8 @@ using System.IO;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs
index 8fd61f2bc..fc0920edf 100644
--- a/Emby.Server.Implementations/Plugins/PluginManager.cs
+++ b/Emby.Server.Implementations/Plugins/PluginManager.cs
@@ -10,8 +10,8 @@ using System.Text.Json;
using System.Threading.Tasks;
using MediaBrowser.Common;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json;
+using Jellyfin.Extensions.Json.Converters;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Configuration;
diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs
index 783185e7d..afc08fc26 100644
--- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs
+++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs
@@ -1,15 +1,12 @@
-#nullable disable
-
using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
+using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.QuickConnect;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.QuickConnect;
@@ -22,9 +19,18 @@ namespace Emby.Server.Implementations.QuickConnect
/// </summary>
public class QuickConnectManager : IQuickConnect, IDisposable
{
- private readonly RNGCryptoServiceProvider _rng = new ();
- private readonly ConcurrentDictionary<string, QuickConnectResult> _currentRequests = new ();
- private readonly ConcurrentDictionary<string, (string Token, Guid UserId)> _quickConnectTokens = new ();
+ /// <summary>
+ /// The length of user facing codes.
+ /// </summary>
+ private const int CodeLength = 6;
+
+ /// <summary>
+ /// The time (in minutes) that the quick connect token is valid.
+ /// </summary>
+ private const int Timeout = 10;
+
+ private readonly RNGCryptoServiceProvider _rng = new();
+ private readonly ConcurrentDictionary<string, QuickConnectResult> _currentRequests = new();
private readonly IServerConfigurationManager _config;
private readonly ILogger<QuickConnectManager> _logger;
@@ -34,80 +40,42 @@ namespace Emby.Server.Implementations.QuickConnect
/// Initializes a new instance of the <see cref="QuickConnectManager"/> class.
/// Should only be called at server startup when a singleton is created.
/// </summary>
- /// <param name="config">The server configuration manager.</param>
- /// <param name="logger">The logger.</param>
- /// <param name="sessionManager">The session manager.</param>
- public QuickConnectManager(IServerConfigurationManager config, ILogger<QuickConnectManager> logger, ISessionManager sessionManager)
+ /// <param name="config">Configuration.</param>
+ /// <param name="logger">Logger.</param>
+ /// <param name="sessionManager">Session Manager.</param>
+ public QuickConnectManager(
+ IServerConfigurationManager config,
+ ILogger<QuickConnectManager> logger,
+ ISessionManager sessionManager)
{
_config = config;
_logger = logger;
_sessionManager = sessionManager;
-
- ReloadConfiguration();
}
- /// <inheritdoc/>
- public int CodeLength { get; set; } = 6;
+ /// <inheritdoc />
+ public bool IsEnabled => _config.Configuration.QuickConnectAvailable;
- /// <inheritdoc/>
- public string TokenName { get; set; } = "QuickConnect";
-
- /// <inheritdoc/>
- public QuickConnectState State { get; private set; } = QuickConnectState.Unavailable;
-
- /// <inheritdoc/>
- public int Timeout { get; set; } = 5;
-
- private DateTime DateActivated { get; set; }
-
- /// <inheritdoc/>
- public void AssertActive()
+ /// <summary>
+ /// Assert that quick connect is currently active and throws an exception if it is not.
+ /// </summary>
+ private void AssertActive()
{
- if (State != QuickConnectState.Active)
+ if (!IsEnabled)
{
- throw new ArgumentException("Quick connect is not active on this server");
+ throw new AuthenticationException("Quick connect is not active on this server");
}
}
/// <inheritdoc/>
- public void Activate()
- {
- DateActivated = DateTime.UtcNow;
- SetState(QuickConnectState.Active);
- }
-
- /// <inheritdoc/>
- public void SetState(QuickConnectState newState)
- {
- _logger.LogDebug("Changed quick connect state from {State} to {newState}", State, newState);
-
- ExpireRequests(true);
-
- State = newState;
- _config.Configuration.QuickConnectAvailable = newState == QuickConnectState.Available || newState == QuickConnectState.Active;
- _config.SaveConfiguration();
-
- _logger.LogDebug("Configuration saved");
- }
-
- /// <inheritdoc/>
public QuickConnectResult TryConnect()
{
+ AssertActive();
ExpireRequests();
- if (State != QuickConnectState.Active)
- {
- _logger.LogDebug("Refusing quick connect initiation request, current state is {State}", State);
- throw new AuthenticationException("Quick connect is not active on this server");
- }
-
+ var secret = GenerateSecureRandom();
var code = GenerateCode();
- var result = new QuickConnectResult()
- {
- Secret = GenerateSecureRandom(),
- DateAdded = DateTime.UtcNow,
- Code = code
- };
+ var result = new QuickConnectResult(secret, code, DateTime.UtcNow);
_currentRequests[code] = result;
return result;
@@ -116,12 +84,12 @@ namespace Emby.Server.Implementations.QuickConnect
/// <inheritdoc/>
public QuickConnectResult CheckRequestStatus(string secret)
{
- ExpireRequests();
AssertActive();
+ ExpireRequests();
string code = _currentRequests.Where(x => x.Value.Secret == secret).Select(x => x.Value.Code).DefaultIfEmpty(string.Empty).First();
- if (!_currentRequests.TryGetValue(code, out QuickConnectResult result))
+ if (!_currentRequests.TryGetValue(code, out QuickConnectResult? result))
{
throw new ResourceNotFoundException("Unable to find request with provided secret");
}
@@ -129,22 +97,11 @@ namespace Emby.Server.Implementations.QuickConnect
return result;
}
- /// <inheritdoc/>
- public void AuthenticateRequest(AuthenticationRequest request, string token)
- {
- if (!_quickConnectTokens.TryGetValue(token, out var entry))
- {
- throw new SecurityException("Unknown quick connect token");
- }
-
- request.UserId = entry.UserId;
- _quickConnectTokens.Remove(token, out _);
-
- _sessionManager.AuthenticateQuickConnect(request, token);
- }
-
- /// <inheritdoc/>
- public string GenerateCode()
+ /// <summary>
+ /// Generates a short code to display to the user to uniquely identify this request.
+ /// </summary>
+ /// <returns>A short, unique alphanumeric string.</returns>
+ private string GenerateCode()
{
Span<byte> raw = stackalloc byte[4];
@@ -163,12 +120,12 @@ namespace Emby.Server.Implementations.QuickConnect
}
/// <inheritdoc/>
- public bool AuthorizeRequest(Guid userId, string code)
+ public async Task<bool> AuthorizeRequest(Guid userId, string code)
{
- ExpireRequests();
AssertActive();
+ ExpireRequests();
- if (!_currentRequests.TryGetValue(code, out QuickConnectResult result))
+ if (!_currentRequests.TryGetValue(code, out QuickConnectResult? result))
{
throw new ResourceNotFoundException("Unable to find request");
}
@@ -178,37 +135,19 @@ namespace Emby.Server.Implementations.QuickConnect
throw new InvalidOperationException("Request is already authorized");
}
- result.Authentication = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
+ var token = Guid.NewGuid();
+ result.Authentication = token;
// Change the time on the request so it expires one minute into the future. It can't expire immediately as otherwise some clients wouldn't ever see that they have been authenticated.
- var added = result.DateAdded ?? DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(Timeout));
- result.DateAdded = added.Subtract(TimeSpan.FromMinutes(Timeout - 1));
+ result.DateAdded = DateTime.Now.Add(TimeSpan.FromMinutes(1));
- _quickConnectTokens[result.Authentication] = (TokenName, userId);
+ await _sessionManager.AuthenticateQuickConnect(userId).ConfigureAwait(false);
_logger.LogDebug("Authorizing device with code {Code} to login as user {userId}", code, userId);
return true;
}
- /// <inheritdoc/>
- public int DeleteAllDevices(Guid user)
- {
- var tokens = _quickConnectTokens
- .Where(entry => entry.Value.Token.StartsWith(TokenName, StringComparison.Ordinal) && entry.Value.UserId == user)
- .ToList();
-
- var removed = 0;
- foreach (var token in tokens)
- {
- _quickConnectTokens.Remove(token.Key, out _);
- _logger.LogDebug("Deleted token {AccessToken}", token.Key);
- removed++;
- }
-
- return removed;
- }
-
/// <summary>
/// Dispose.
/// </summary>
@@ -226,7 +165,7 @@ namespace Emby.Server.Implementations.QuickConnect
{
if (disposing)
{
- _rng?.Dispose();
+ _rng.Dispose();
}
}
@@ -238,22 +177,19 @@ namespace Emby.Server.Implementations.QuickConnect
return Convert.ToHexString(bytes);
}
- /// <inheritdoc/>
- public void ExpireRequests(bool expireAll = false)
+ /// <summary>
+ /// Expire quick connect requests that are over the time limit. If <paramref name="expireAll"/> is true, all requests are unconditionally expired.
+ /// </summary>
+ /// <param name="expireAll">If true, all requests will be expired.</param>
+ private void ExpireRequests(bool expireAll = false)
{
- // Check if quick connect should be deactivated
- if (State == QuickConnectState.Active && DateTime.UtcNow > DateActivated.AddMinutes(Timeout) && !expireAll)
- {
- _logger.LogDebug("Quick connect time expired, deactivating");
- SetState(QuickConnectState.Available);
- expireAll = true;
- }
+ // All requests before this timestamp have expired
+ var minTime = DateTime.UtcNow.AddMinutes(-Timeout);
// Expire stale connection requests
foreach (var (_, currentRequest) in _currentRequests)
{
- var added = currentRequest.DateAdded ?? DateTime.UnixEpoch;
- if (expireAll || DateTime.UtcNow > added.AddMinutes(Timeout))
+ if (expireAll || currentRequest.DateAdded > minTime)
{
var code = currentRequest.Code;
_logger.LogDebug("Removing expired request {Code}", code);
@@ -265,10 +201,5 @@ namespace Emby.Server.Implementations.QuickConnect
}
}
}
-
- private void ReloadConfiguration()
- {
- State = _config.Configuration.QuickConnectAvailable ? QuickConnectState.Available : QuickConnectState.Unavailable;
- }
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index d7e320754..b34325041 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
using Jellyfin.Data.Events;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Progress;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 544c8e5fd..29b545583 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -14,6 +14,7 @@ using Jellyfin.Data.Entities.Security;
using Jellyfin.Data.Enums;
using Jellyfin.Data.Events;
using Jellyfin.Data.Queries;
+using Jellyfin.Extensions;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller;
@@ -1438,9 +1439,9 @@ namespace Emby.Server.Implementations.Session
return AuthenticateNewSessionInternal(request, true);
}
- public Task<AuthenticationResult> AuthenticateQuickConnect(AuthenticationRequest request, string token)
+ public Task<AuthenticationResult> AuthenticateQuickConnect(Guid userId)
{
- return AuthenticateNewSessionInternal(request, false);
+ return AuthenticateNewSessionInternal(new AuthenticationRequest { UserId = userId }, false);
}
private async Task<AuthenticationResult> AuthenticateNewSessionInternal(AuthenticationRequest request, bool enforcePassword)
diff --git a/Emby.Server.Implementations/Sorting/StudioComparer.cs b/Emby.Server.Implementations/Sorting/StudioComparer.cs
index 01445c525..6826aee3b 100644
--- a/Emby.Server.Implementations/Sorting/StudioComparer.cs
+++ b/Emby.Server.Implementations/Sorting/StudioComparer.cs
@@ -4,6 +4,7 @@
using System;
using System.Linq;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying;
@@ -30,7 +31,7 @@ namespace Emby.Server.Implementations.Sorting
throw new ArgumentNullException(nameof(y));
}
- return AlphanumComparator.CompareValues(x.Studios.FirstOrDefault() ?? string.Empty, y.Studios.FirstOrDefault() ?? string.Empty);
+ return AlphanumericComparator.CompareValues(x.Studios.FirstOrDefault(), y.Studios.FirstOrDefault());
}
/// <summary>
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index b0921cbd8..7b0afa4e2 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -11,7 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Events;
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
diff --git a/Jellyfin.Api/BaseJellyfinApiController.cs b/Jellyfin.Api/BaseJellyfinApiController.cs
index 1c1fc71d7..59d6b7513 100644
--- a/Jellyfin.Api/BaseJellyfinApiController.cs
+++ b/Jellyfin.Api/BaseJellyfinApiController.cs
@@ -1,5 +1,5 @@
using System.Net.Mime;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using Microsoft.AspNetCore.Mvc;
namespace Jellyfin.Api
diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs
index b6309baab..60529e990 100644
--- a/Jellyfin.Api/Controllers/ConfigurationController.cs
+++ b/Jellyfin.Api/Controllers/ConfigurationController.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Models.ConfigurationDtos;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Configuration;
diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs
index 7a6130719..0ae6109bc 100644
--- a/Jellyfin.Api/Controllers/PluginsController.cs
+++ b/Jellyfin.Api/Controllers/PluginsController.cs
@@ -8,8 +8,8 @@ using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Models.PluginDtos;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Json;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
using MediaBrowser.Model.Net;
diff --git a/Jellyfin.Api/Controllers/QuickConnectController.cs b/Jellyfin.Api/Controllers/QuickConnectController.cs
index 4ac849181..56fef08a9 100644
--- a/Jellyfin.Api/Controllers/QuickConnectController.cs
+++ b/Jellyfin.Api/Controllers/QuickConnectController.cs
@@ -1,7 +1,9 @@
using System.ComponentModel.DataAnnotations;
+using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.QuickConnect;
using MediaBrowser.Model.QuickConnect;
using Microsoft.AspNetCore.Authorization;
@@ -30,13 +32,12 @@ namespace Jellyfin.Api.Controllers
/// Gets the current quick connect state.
/// </summary>
/// <response code="200">Quick connect state returned.</response>
- /// <returns>The current <see cref="QuickConnectState"/>.</returns>
- [HttpGet("Status")]
+ /// <returns>Whether Quick Connect is enabled on the server or not.</returns>
+ [HttpGet("Enabled")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QuickConnectState> GetStatus()
+ public ActionResult<bool> GetEnabled()
{
- _quickConnect.ExpireRequests();
- return _quickConnect.State;
+ return _quickConnect.IsEnabled;
}
/// <summary>
@@ -49,7 +50,14 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QuickConnectResult> Initiate()
{
- return _quickConnect.TryConnect();
+ try
+ {
+ return _quickConnect.TryConnect();
+ }
+ catch (AuthenticationException)
+ {
+ return Unauthorized("Quick connect is disabled");
+ }
}
/// <summary>
@@ -72,42 +80,10 @@ namespace Jellyfin.Api.Controllers
{
return NotFound("Unknown secret");
}
- }
-
- /// <summary>
- /// Temporarily activates quick connect for five minutes.
- /// </summary>
- /// <response code="204">Quick connect has been temporarily activated.</response>
- /// <response code="403">Quick connect is unavailable on this server.</response>
- /// <returns>An <see cref="NoContentResult"/> on success.</returns>
- [HttpPost("Activate")]
- [Authorize(Policy = Policies.DefaultAuthorization)]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- public ActionResult Activate()
- {
- if (_quickConnect.State == QuickConnectState.Unavailable)
+ catch (AuthenticationException)
{
- return StatusCode(StatusCodes.Status403Forbidden, "Quick connect is unavailable");
+ return Unauthorized("Quick connect is disabled");
}
-
- _quickConnect.Activate();
- return NoContent();
- }
-
- /// <summary>
- /// Enables or disables quick connect.
- /// </summary>
- /// <param name="status">New <see cref="QuickConnectState"/>.</param>
- /// <response code="204">Quick connect state set successfully.</response>
- /// <returns>An <see cref="NoContentResult"/> on success.</returns>
- [HttpPost("Available")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- public ActionResult Available([FromQuery] QuickConnectState status = QuickConnectState.Available)
- {
- _quickConnect.SetState(status);
- return NoContent();
}
/// <summary>
@@ -121,7 +97,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
- public ActionResult<bool> Authorize([FromQuery, Required] string code)
+ public async Task<ActionResult<bool>> Authorize([FromQuery, Required] string code)
{
var userId = ClaimHelpers.GetUserId(Request.HttpContext.User);
if (!userId.HasValue)
@@ -129,26 +105,14 @@ namespace Jellyfin.Api.Controllers
return StatusCode(StatusCodes.Status403Forbidden, "Unknown user id");
}
- return _quickConnect.AuthorizeRequest(userId.Value, code);
- }
-
- /// <summary>
- /// Deauthorize all quick connect devices for the current user.
- /// </summary>
- /// <response code="200">All quick connect devices were deleted.</response>
- /// <returns>The number of devices that were deleted.</returns>
- [HttpPost("Deauthorize")]
- [Authorize(Policy = Policies.DefaultAuthorization)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<int> Deauthorize()
- {
- var userId = ClaimHelpers.GetUserId(Request.HttpContext.User);
- if (!userId.HasValue)
+ try
{
- return 0;
+ return await _quickConnect.AuthorizeRequest(userId.Value, code).ConfigureAwait(false);
+ }
+ catch (AuthenticationException)
+ {
+ return Unauthorized("Quick connect is disabled");
}
-
- return _quickConnect.DeleteAllDevices(userId.Value);
}
}
}
diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs
index ffb726fab..51d40994e 100644
--- a/Jellyfin.Api/Controllers/TvShowsController.cs
+++ b/Jellyfin.Api/Controllers/TvShowsController.cs
@@ -6,7 +6,7 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 1d70406ac..a33a0826c 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -9,7 +9,7 @@ using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
diff --git a/Jellyfin.Api/Extensions/DtoExtensions.cs b/Jellyfin.Api/Extensions/DtoExtensions.cs
index 06173315a..5e338b67d 100644
--- a/Jellyfin.Api/Extensions/DtoExtensions.cs
+++ b/Jellyfin.Api/Extensions/DtoExtensions.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using Jellyfin.Api.Helpers;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
diff --git a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs
index 8913180e4..411e4c550 100644
--- a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs
+++ b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Jellyfin.Data.Enums;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
diff --git a/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs b/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs
index 65d4b644e..0761b2085 100644
--- a/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs
+++ b/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
namespace Jellyfin.Api.Models.PlaylistDtos
{
diff --git a/Jellyfin.Api/Models/SessionDtos/ClientCapabilitiesDto.cs b/Jellyfin.Api/Models/SessionDtos/ClientCapabilitiesDto.cs
index e58095536..fa62472e1 100644
--- a/Jellyfin.Api/Models/SessionDtos/ClientCapabilitiesDto.cs
+++ b/Jellyfin.Api/Models/SessionDtos/ClientCapabilitiesDto.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Session;
@@ -85,4 +85,4 @@ namespace Jellyfin.Api.Models.SessionDtos
};
}
}
-} \ No newline at end of file
+}
diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
index 8f0fae3be..6d0a5ac2b 100644
--- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs
+++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using BlurHashSharp.SkiaSharp;
+using Diacritics.Extensions;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Drawing;
using Microsoft.Extensions.Logging;
using SkiaSharp;
@@ -142,9 +142,6 @@ namespace Jellyfin.Drawing.Skia
return BlurHashEncoder.Encode(xComp, yComp, path, 128, 128);
}
- private static bool HasDiacritics(string text)
- => !string.Equals(text, text.RemoveDiacritics(), StringComparison.Ordinal);
-
private bool RequiresSpecialCharacterHack(string path)
{
for (int i = 0; i < path.Length; i++)
@@ -155,7 +152,7 @@ namespace Jellyfin.Drawing.Skia
}
}
- return HasDiacritics(path);
+ return path.HasDiacritics();
}
private string NormalizePath(string path)
diff --git a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs
index 97704386a..08970f84d 100644
--- a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs
+++ b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs
@@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using Microsoft.AspNetCore.Http;
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index 924b250ce..15dc43856 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -21,11 +21,11 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Controllers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
+using Jellyfin.Extensions.Json;
using Jellyfin.Networking.Configuration;
using Jellyfin.Server.Configuration;
using Jellyfin.Server.Filters;
using Jellyfin.Server.Formatters;
-using MediaBrowser.Common.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Entities;
using Microsoft.AspNetCore.Authentication;
diff --git a/Jellyfin.Server/Formatters/CamelCaseJsonProfileFormatter.cs b/Jellyfin.Server/Formatters/CamelCaseJsonProfileFormatter.cs
index c349e3dca..ea8c5ecdb 100644
--- a/Jellyfin.Server/Formatters/CamelCaseJsonProfileFormatter.cs
+++ b/Jellyfin.Server/Formatters/CamelCaseJsonProfileFormatter.cs
@@ -1,4 +1,4 @@
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
diff --git a/Jellyfin.Server/Formatters/PascalCaseJsonProfileFormatter.cs b/Jellyfin.Server/Formatters/PascalCaseJsonProfileFormatter.cs
index 0480f5e0e..03ca7dda7 100644
--- a/Jellyfin.Server/Formatters/PascalCaseJsonProfileFormatter.cs
+++ b/Jellyfin.Server/Formatters/PascalCaseJsonProfileFormatter.cs
@@ -1,5 +1,5 @@
using System.Net.Mime;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
diff --git a/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs b/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs
index 310a3d31a..c1f5b5dfa 100644
--- a/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs
+++ b/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs
@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Primitives;
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
index 96bd2ccc4..d9524645a 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
@@ -4,9 +4,9 @@ using Emby.Server.Implementations.Data;
using Emby.Server.Implementations.Serialization;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Extensions.Json;
using Jellyfin.Server.Implementations;
using Jellyfin.Server.Implementations.Users;
-using MediaBrowser.Common.Json;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
diff --git a/Jellyfin.sln b/Jellyfin.sln
index 9fbd9d266..4626601c3 100644
--- a/Jellyfin.sln
+++ b/Jellyfin.sln
@@ -83,6 +83,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Server.Integration
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Providers.Tests", "tests\Jellyfin.Providers.Tests\Jellyfin.Providers.Tests.csproj", "{A964008C-2136-4716-B6CB-B3426C22320A}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Extensions", "src\Jellyfin.Extensions\Jellyfin.Extensions.csproj", "{750B8757-BE3D-4F8C-941A-FBAD94904ADA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Extensions.Tests", "tests\Jellyfin.Extensions.Tests\Jellyfin.Extensions.Tests.csproj", "{332A5C7A-F907-47CA-910E-BE6F7371B9E0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -229,6 +235,14 @@ Global
{A964008C-2136-4716-B6CB-B3426C22320A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A964008C-2136-4716-B6CB-B3426C22320A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A964008C-2136-4716-B6CB-B3426C22320A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {750B8757-BE3D-4F8C-941A-FBAD94904ADA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {750B8757-BE3D-4F8C-941A-FBAD94904ADA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {750B8757-BE3D-4F8C-941A-FBAD94904ADA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {750B8757-BE3D-4F8C-941A-FBAD94904ADA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {332A5C7A-F907-47CA-910E-BE6F7371B9E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {332A5C7A-F907-47CA-910E-BE6F7371B9E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {332A5C7A-F907-47CA-910E-BE6F7371B9E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {332A5C7A-F907-47CA-910E-BE6F7371B9E0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -247,6 +261,8 @@ Global
{3ADBCD8C-C0F2-4956-8FDC-35D686B74CF9} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{68B0B823-A5AC-4E8B-82EA-965AAC7BF76E} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{A964008C-2136-4716-B6CB-B3426C22320A} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {750B8757-BE3D-4F8C-941A-FBAD94904ADA} = {C9F0AB5D-F4D7-40C8-A353-3305C86D6D4C}
+ {332A5C7A-F907-47CA-910E-BE6F7371B9E0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3448830C-EBDC-426C-85CD-7BBB9651A7FE}
diff --git a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
index ffc274c5d..97f40b537 100644
--- a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
+++ b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
@@ -3,7 +3,7 @@
using System;
using System.Linq;
using System.Threading;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index c0cd81110..53fcdbf42 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -8,9 +8,9 @@ using System.Linq;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using Diacritics.Extensions;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
-using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index a682a2e58..b1559ff24 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -5,7 +5,7 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Controller.Extensions;
+using Diacritics.Extensions;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities.Audio
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 6137ddbf7..e5be5421a 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -11,13 +11,14 @@ using System.Text;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using Diacritics.Extensions;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 4a721ca44..4f367fe2b 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -10,7 +10,7 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs
index 244cc00be..d8bc0069c 100644
--- a/MediaBrowser.Controller/Entities/Extensions.cs
+++ b/MediaBrowser.Controller/Entities/Extensions.cs
@@ -2,7 +2,7 @@
using System;
using System.Linq;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index b80a5be3b..338f96204 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -5,8 +5,8 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
+using Diacritics.Extensions;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Extensions;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index 913f76d3b..b0ab280af 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -5,7 +5,7 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Controller.Extensions;
+using Diacritics.Extensions;
using MediaBrowser.Controller.Providers;
using Microsoft.Extensions.Logging;
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index 6fd0a6c6c..888b30001 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -5,7 +5,7 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Controller.Extensions;
+using Diacritics.Extensions;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs
deleted file mode 100644
index f1af01345..000000000
--- a/MediaBrowser.Controller/Extensions/StringExtensions.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-
-namespace MediaBrowser.Controller.Extensions
-{
- /// <summary>
- /// Class BaseExtensions.
- /// </summary>
- public static class StringExtensions
- {
- public static string RemoveDiacritics(this string text)
- {
- var chars = Normalize(text, NormalizationForm.FormD)
- .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark);
-
- return Normalize(string.Concat(chars), NormalizationForm.FormC);
- }
-
- /// <summary>
- /// Counts the number of occurrences of [needle] in the string.
- /// </summary>
- /// <param name="value">The haystack to search in.</param>
- /// <param name="needle">The character to search for.</param>
- /// <returns>The number of occurrences of the [needle] character.</returns>
- public static int Count(this ReadOnlySpan<char> value, char needle)
- {
- var count = 0;
- var length = value.Length;
- for (var i = 0; i < length; i++)
- {
- if (value[i] == needle)
- {
- count++;
- }
- }
-
- return count;
- }
-
- private static string Normalize(string text, NormalizationForm form, bool stripStringOnFailure = true)
- {
- if (stripStringOnFailure)
- {
- try
- {
- return text.Normalize(form);
- }
- catch (ArgumentException)
- {
- // will throw if input contains invalid unicode chars
- // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/
- text = Regex.Replace(text, "([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])", string.Empty);
- return Normalize(text, form, false);
- }
- }
-
- try
- {
- return text.Normalize(form);
- }
- catch (ArgumentException)
- {
- // if it still fails, return the original text
- return text;
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs
index 29bfeca09..a49dcacc1 100644
--- a/MediaBrowser.Controller/Library/NameExtensions.cs
+++ b/MediaBrowser.Controller/Library/NameExtensions.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Diacritics.Extensions;
using MediaBrowser.Controller.Extensions;
namespace MediaBrowser.Controller.Library
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index ee76ff080..4bed112e4 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -14,6 +14,7 @@
</PropertyGroup>
<ItemGroup>
+ <PackageReference Include="Diacritics" Version="2.1.20036.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs
index 59003b187..616409533 100644
--- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs
+++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs
@@ -1,6 +1,5 @@
-#nullable disable
-
using System;
+using System.Threading.Tasks;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.QuickConnect;
@@ -12,40 +11,9 @@ namespace MediaBrowser.Controller.QuickConnect
public interface IQuickConnect
{
/// <summary>
- /// Gets or sets the length of user facing codes.
- /// </summary>
- int CodeLength { get; set; }
-
- /// <summary>
- /// Gets or sets the name of internal access tokens.
- /// </summary>
- string TokenName { get; set; }
-
- /// <summary>
- /// Gets the current state of quick connect.
- /// </summary>
- QuickConnectState State { get; }
-
- /// <summary>
- /// Gets or sets the time (in minutes) before quick connect will automatically deactivate.
- /// </summary>
- int Timeout { get; set; }
-
- /// <summary>
- /// Assert that quick connect is currently active and throws an exception if it is not.
- /// </summary>
- void AssertActive();
-
- /// <summary>
- /// Temporarily activates quick connect for a short amount of time.
+ /// Gets a value indicating whether quick connect is enabled or not.
/// </summary>
- void Activate();
-
- /// <summary>
- /// Changes the state of quick connect.
- /// </summary>
- /// <param name="newState">New state to change to.</param>
- void SetState(QuickConnectState newState);
+ bool IsEnabled { get; }
/// <summary>
/// Initiates a new quick connect request.
@@ -61,37 +29,11 @@ namespace MediaBrowser.Controller.QuickConnect
QuickConnectResult CheckRequestStatus(string secret);
/// <summary>
- /// Authenticates a QuickConnect request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="token">The token.</param>
- void AuthenticateRequest(AuthenticationRequest request, string token);
-
- /// <summary>
/// Authorizes a quick connect request to connect as the calling user.
/// </summary>
/// <param name="userId">User id.</param>
/// <param name="code">Identifying code for the request.</param>
/// <returns>A boolean indicating if the authorization completed successfully.</returns>
- bool AuthorizeRequest(Guid userId, string code);
-
- /// <summary>
- /// Expire quick connect requests that are over the time limit. If <paramref name="expireAll"/> is true, all requests are unconditionally expired.
- /// </summary>
- /// <param name="expireAll">If true, all requests will be expired.</param>
- void ExpireRequests(bool expireAll = false);
-
- /// <summary>
- /// Deletes all quick connect access tokens for the provided user.
- /// </summary>
- /// <param name="user">Guid of the user to delete tokens for.</param>
- /// <returns>A count of the deleted tokens.</returns>
- int DeleteAllDevices(Guid user);
-
- /// <summary>
- /// Generates a short code to display to the user to uniquely identify this request.
- /// </summary>
- /// <returns>A short, unique alphanumeric string.</returns>
- string GenerateCode();
+ Task<bool> AuthorizeRequest(Guid userId, string code);
}
}
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index 1000da247..8be9ff521 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -276,10 +276,9 @@ namespace MediaBrowser.Controller.Session
/// <summary>
/// Authenticates a new session with quick connect.
/// </summary>
- /// <param name="request">The request.</param>
- /// <param name="token">Quick connect access token.</param>
+ /// <param name="userId">The user id.</param>
/// <returns>Task{SessionInfo}.</returns>
- Task<AuthenticationResult> AuthenticateQuickConnect(AuthenticationRequest request, string token);
+ Task<AuthenticationResult> AuthenticateQuickConnect(Guid userId);
/// <summary>
/// Reports the capabilities.
diff --git a/MediaBrowser.Controller/Sorting/SortExtensions.cs b/MediaBrowser.Controller/Sorting/SortExtensions.cs
index aa6ec513f..f9c0d39dd 100644
--- a/MediaBrowser.Controller/Sorting/SortExtensions.cs
+++ b/MediaBrowser.Controller/Sorting/SortExtensions.cs
@@ -1,16 +1,15 @@
-#nullable disable
-
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Linq;
+using Jellyfin.Extensions;
namespace MediaBrowser.Controller.Sorting
{
public static class SortExtensions
{
- private static readonly AlphanumComparator _comparer = new AlphanumComparator();
+ private static readonly AlphanumericComparator _comparer = new AlphanumericComparator();
public static IEnumerable<T> OrderByString<T>(this IEnumerable<T> list, Func<T, string> getName)
{
diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
index fdba64c4a..dc13bf4f6 100644
--- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 3af618af8..412a95321 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -11,9 +11,9 @@ using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.MediaEncoding.Probing;
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs
index 639a34d99..24ceb1b57 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs
@@ -2,7 +2,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Logging;
using Nikse.SubtitleEdit.Core;
diff --git a/MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs b/MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs
index e7fe8d6af..9b39f9e11 100644
--- a/MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs
+++ b/MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs
@@ -2,25 +2,28 @@
namespace MediaBrowser.Model.Dlna
{
+ /// <summary>
+ /// Delivery method to use during playback of a specific subtitle format.
+ /// </summary>
public enum SubtitleDeliveryMethod
{
/// <summary>
- /// The encode.
+ /// Burn the subtitles in the video track.
/// </summary>
Encode = 0,
/// <summary>
- /// The embed.
+ /// Embed the subtitles in the file or stream.
/// </summary>
Embed = 1,
/// <summary>
- /// The external.
+ /// Serve the subtitles as an external file.
/// </summary>
External = 2,
/// <summary>
- /// The HLS.
+ /// Serve the subtitles as a separate HLS stream.
/// </summary>
Hls = 3
}
diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
index 8fed392b9..2b2bda12c 100644
--- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
+++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
@@ -3,6 +3,7 @@
using System;
using System.Text.Json.Serialization;
+using Jellyfin.Extensions.Json.Converters;
using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Model.Entities
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 4db99f0b0..c475d905a 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -50,7 +50,8 @@
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\Jellyfin.Data\Jellyfin.Data.csproj" />
+ <ProjectReference Include="../Jellyfin.Data/Jellyfin.Data.csproj" />
+ <ProjectReference Include="../src/Jellyfin.Extensions/Jellyfin.Extensions.csproj" />
</ItemGroup>
</Project>
diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs
index 0fa40b6a7..d180d2986 100644
--- a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs
+++ b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs
@@ -3,38 +3,46 @@ using System;
namespace MediaBrowser.Model.QuickConnect
{
/// <summary>
- /// Stores the result of an incoming quick connect request.
+ /// Stores the state of an quick connect request.
/// </summary>
public class QuickConnectResult
{
/// <summary>
- /// Gets a value indicating whether this request is authorized.
+ /// Initializes a new instance of the <see cref="QuickConnectResult"/> class.
/// </summary>
- public bool Authenticated => !string.IsNullOrEmpty(Authentication);
+ /// <param name="secret">The secret used to query the request state.</param>
+ /// <param name="code">The code used to allow the request.</param>
+ /// <param name="dateAdded">The time when the request was created.</param>
+ public QuickConnectResult(string secret, string code, DateTime dateAdded)
+ {
+ Secret = secret;
+ Code = code;
+ DateAdded = dateAdded;
+ }
/// <summary>
- /// Gets or sets the secret value used to uniquely identify this request. Can be used to retrieve authentication information.
+ /// Gets a value indicating whether this request is authorized.
/// </summary>
- public string? Secret { get; set; }
+ public bool Authenticated => Authentication != null;
/// <summary>
- /// Gets or sets the user facing code used so the user can quickly differentiate this request from others.
+ /// Gets the secret value used to uniquely identify this request. Can be used to retrieve authentication information.
/// </summary>
- public string? Code { get; set; }
+ public string Secret { get; }
/// <summary>
- /// Gets or sets the private access token.
+ /// Gets the user facing code used so the user can quickly differentiate this request from others.
/// </summary>
- public string? Authentication { get; set; }
+ public string Code { get; }
/// <summary>
- /// Gets or sets an error message.
+ /// Gets or sets the private access token.
/// </summary>
- public string? Error { get; set; }
+ public Guid? Authentication { get; set; }
/// <summary>
/// Gets or sets the DateTime that this request was created.
/// </summary>
- public DateTime? DateAdded { get; set; }
+ public DateTime DateAdded { get; set; }
}
}
diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectState.cs b/MediaBrowser.Model/QuickConnect/QuickConnectState.cs
deleted file mode 100644
index f1074f25f..000000000
--- a/MediaBrowser.Model/QuickConnect/QuickConnectState.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace MediaBrowser.Model.QuickConnect
-{
- /// <summary>
- /// Quick connect state.
- /// </summary>
- public enum QuickConnectState
- {
- /// <summary>
- /// This feature has not been opted into and is unavailable until the server administrator chooses to opt-in.
- /// </summary>
- Unavailable = 0,
-
- /// <summary>
- /// The feature is enabled for use on the server but is not currently accepting connection requests.
- /// </summary>
- Available = 1,
-
- /// <summary>
- /// The feature is actively accepting connection requests.
- /// </summary>
- Active = 2
- }
-}
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
index e5aa64b28..aceba2215 100644
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs
@@ -3,9 +3,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Diacritics.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs
index 85a28747f..36d8eeb40 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs
@@ -6,7 +6,7 @@ using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs
index 25bb3f9ce..9539c396d 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs
@@ -11,7 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.Audio;
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs
index db8536cc9..aa61a56f6 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs
@@ -6,7 +6,7 @@ using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs
index cbb61fa35..b2f05d76d 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs
@@ -10,7 +10,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.Audio;
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs
index 2eab95294..0cae7768a 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs
@@ -11,8 +11,8 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using Diacritics.Extensions;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
@@ -53,7 +53,7 @@ namespace MediaBrowser.Providers.Music
}
}
- if (HasDiacritics(searchInfo.Name))
+ if (searchInfo.Name.HasDiacritics())
{
// Try again using the search with accent characters url
url = string.Format(CultureInfo.InvariantCulture, "/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
@@ -252,16 +252,6 @@ namespace MediaBrowser.Providers.Music
}
/// <summary>
- /// Determines whether the specified text has diacritics.
- /// </summary>
- /// <param name="text">The text.</param>
- /// <returns><c>true</c> if the specified text has diacritics; otherwise, <c>false</c>.</returns>
- private bool HasDiacritics(string text)
- {
- return !string.Equals(text, text.RemoveDiacritics(), StringComparison.Ordinal);
- }
-
- /// <summary>
/// Encodes an URL.
/// </summary>
/// <param name="name">The name.</param>
diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableInt32Converter.cs b/MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableInt32Converter.cs
index 3d97a9de5..268538815 100644
--- a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableInt32Converter.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableInt32Converter.cs
@@ -1,9 +1,11 @@
-using System;
+#nullable enable
+
+using System;
using System.ComponentModel;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace MediaBrowser.Providers.Plugins.Omdb
{
/// <summary>
/// Converts a string <c>N/A</c> to <c>string.Empty</c>.
diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs b/MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableStringConverter.cs
index 77cf46b70..c19589d45 100644
--- a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableStringConverter.cs
@@ -1,8 +1,10 @@
-using System;
+#nullable enable
+
+using System;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace MediaBrowser.Providers.Plugins.Omdb
{
/// <summary>
/// Converts a string <c>N/A</c> to <c>string.Empty</c>.
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
index 428b0ded1..78eea02e0 100644
--- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
@@ -10,8 +10,8 @@ using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
-using MediaBrowser.Common.Json;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json;
+using Jellyfin.Extensions.Json.Converters;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
index 46d303890..5d9fd36d3 100644
--- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
@@ -10,8 +10,8 @@ using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
-using MediaBrowser.Common.Json;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json;
+using Jellyfin.Extensions.Json.Converters;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Providers/Properties/AssemblyInfo.cs b/MediaBrowser.Providers/Properties/AssemblyInfo.cs
index fe4749c79..bd301b5f0 100644
--- a/MediaBrowser.Providers/Properties/AssemblyInfo.cs
+++ b/MediaBrowser.Providers/Properties/AssemblyInfo.cs
@@ -15,7 +15,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
-[assembly: InternalsVisibleTo("Jellyfin.Common.Tests")]
+[assembly: InternalsVisibleTo("Jellyfin.Providers.Tests")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
index f6153dd53..63e78d15e 100644
--- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
+++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
@@ -8,7 +8,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
diff --git a/debian/rules b/debian/rules
index 96541f41b..64e2b48ea 100755
--- a/debian/rules
+++ b/debian/rules
@@ -39,7 +39,7 @@ override_dh_auto_test:
override_dh_clistrip:
override_dh_auto_build:
- dotnet publish --configuration $(CONFIG) --output='$(CURDIR)/usr/lib/jellyfin/bin' --self-contained --runtime $(DOTNETRUNTIME) \
+ dotnet publish -maxcpucount:1 --configuration $(CONFIG) --output='$(CURDIR)/usr/lib/jellyfin/bin' --self-contained --runtime $(DOTNETRUNTIME) \
"-p:DebugSymbols=false;DebugType=none" Jellyfin.Server
override_dh_auto_clean:
diff --git a/MediaBrowser.Controller/Sorting/AlphanumComparator.cs b/src/Jellyfin.Extensions/AlphanumericComparator.cs
index e00cadca2..e3c81eba8 100644
--- a/MediaBrowser.Controller/Sorting/AlphanumComparator.cs
+++ b/src/Jellyfin.Extensions/AlphanumericComparator.cs
@@ -1,12 +1,19 @@
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
-namespace MediaBrowser.Controller.Sorting
+namespace Jellyfin.Extensions
{
- public class AlphanumComparator : IComparer<string?>
+ /// <summary>
+ /// Alphanumeric <see cref="IComparer{T}" />.
+ /// </summary>
+ public class AlphanumericComparator : IComparer<string?>
{
+ /// <summary>
+ /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
+ /// </summary>
+ /// <param name="s1">The first object to compare.</param>
+ /// <param name="s2">The second object to compare.</param>
+ /// <returns>A signed integer that indicates the relative values of <c>x</c> and <c>y</c>.</returns>
public static int CompareValues(string? s1, string? s2)
{
if (s1 == null && s2 == null)
diff --git a/MediaBrowser.Common/Extensions/CopyToExtensions.cs b/src/Jellyfin.Extensions/CopyToExtensions.cs
index 2ecbc6539..72d37b5b6 100644
--- a/MediaBrowser.Common/Extensions/CopyToExtensions.cs
+++ b/src/Jellyfin.Extensions/CopyToExtensions.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace MediaBrowser.Common.Extensions
+namespace Jellyfin.Extensions
{
/// <summary>
/// Provides <c>CopyTo</c> extensions methods for <see cref="IReadOnlyList{T}" />.
diff --git a/MediaBrowser.Common/Extensions/EnumerableExtensions.cs b/src/Jellyfin.Extensions/EnumerableExtensions.cs
index 2b8a6c395..b5fe93357 100644
--- a/MediaBrowser.Common/Extensions/EnumerableExtensions.cs
+++ b/src/Jellyfin.Extensions/EnumerableExtensions.cs
@@ -1,7 +1,7 @@
-using System;
+using System;
using System.Collections.Generic;
-namespace MediaBrowser.Common.Extensions
+namespace Jellyfin.Extensions
{
/// <summary>
/// Static extensions for the <see cref="IEnumerable{T}"/> interface.
diff --git a/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj
new file mode 100644
index 000000000..f343be1e3
--- /dev/null
+++ b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj
@@ -0,0 +1,30 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
+ <AnalysisMode>AllEnabledByDefault</AnalysisMode>
+ <CodeAnalysisRuleSet>../../jellyfin.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <Authors>Jellyfin Contributors</Authors>
+ <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
+ <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="../../SharedVersion.cs" />
+ </ItemGroup>
+
+ <!-- Code Analyzers-->
+ <ItemGroup>
+ <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+ </ItemGroup>
+
+</Project>
diff --git a/MediaBrowser.Common/Json/Converters/JsonBoolNumberConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonBoolNumberConverter.cs
index b29e6a71a..c2543cf7c 100644
--- a/MediaBrowser.Common/Json/Converters/JsonBoolNumberConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonBoolNumberConverter.cs
@@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Converts a number to a boolean.
@@ -27,4 +27,4 @@ namespace MediaBrowser.Common.Json.Converters
writer.WriteBooleanValue(value);
}
}
-} \ No newline at end of file
+}
diff --git a/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs
index 127a41a06..44980ec02 100644
--- a/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs
@@ -3,7 +3,7 @@ using System.ComponentModel;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Convert comma delimited string to array of type.
diff --git a/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs
index de41348dd..cc9311a24 100644
--- a/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs
@@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Json comma delimited array converter factory.
diff --git a/MediaBrowser.Common/Json/Converters/JsonDateTimeConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonDateTimeConverter.cs
index 73e3a0493..8ae080b15 100644
--- a/MediaBrowser.Common/Json/Converters/JsonDateTimeConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonDateTimeConverter.cs
@@ -3,7 +3,7 @@ using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Legacy DateTime converter.
@@ -31,4 +31,4 @@ namespace MediaBrowser.Common.Json.Converters
}
}
}
-} \ No newline at end of file
+}
diff --git a/MediaBrowser.Common/Json/Converters/JsonDelimitedArrayConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonDelimitedArrayConverter.cs
index b691798c9..c39805aa3 100644
--- a/MediaBrowser.Common/Json/Converters/JsonDelimitedArrayConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonDelimitedArrayConverter.cs
@@ -3,7 +3,7 @@ using System.ComponentModel;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Convert delimited string to array of type.
diff --git a/MediaBrowser.Common/Json/Converters/JsonGuidConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonGuidConverter.cs
index bd9600110..be94dd519 100644
--- a/MediaBrowser.Common/Json/Converters/JsonGuidConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonGuidConverter.cs
@@ -3,7 +3,7 @@ using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Converts a GUID object or value to/from JSON.
diff --git a/MediaBrowser.Model/Entities/JsonLowerCaseConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonLowerCaseConverter.cs
index 7c627f0e3..cd582ced6 100644
--- a/MediaBrowser.Model/Entities/JsonLowerCaseConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonLowerCaseConverter.cs
@@ -1,12 +1,8 @@
-#nullable disable
-// THIS IS A HACK
-// TODO: @bond Move to separate project
-
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Model.Entities
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Converts an object to a lowercase string.
@@ -15,7 +11,7 @@ namespace MediaBrowser.Model.Entities
public class JsonLowerCaseConverter<T> : JsonConverter<T>
{
/// <inheritdoc />
- public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return JsonSerializer.Deserialize<T>(ref reader, options);
}
@@ -23,7 +19,7 @@ namespace MediaBrowser.Model.Entities
/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
- writer.WriteStringValue(value?.ToString().ToLowerInvariant());
+ writer.WriteStringValue(value?.ToString()?.ToLowerInvariant());
}
}
}
diff --git a/MediaBrowser.Common/Json/Converters/JsonNullableGuidConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonNullableGuidConverter.cs
index 6d96d5496..6192d1598 100644
--- a/MediaBrowser.Common/Json/Converters/JsonNullableGuidConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonNullableGuidConverter.cs
@@ -3,7 +3,7 @@ using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Converts a GUID object or value to/from JSON.
diff --git a/MediaBrowser.Common/Json/Converters/JsonNullableStructConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverter.cs
index 0501f7b2a..6de238b39 100644
--- a/MediaBrowser.Common/Json/Converters/JsonNullableStructConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverter.cs
@@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Converts a nullable struct or value to/from JSON.
diff --git a/MediaBrowser.Common/Json/Converters/JsonNullableStructConverterFactory.cs b/src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverterFactory.cs
index e2a3d798a..e7749589a 100644
--- a/MediaBrowser.Common/Json/Converters/JsonNullableStructConverterFactory.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverterFactory.cs
@@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Json nullable struct converter factory.
diff --git a/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs
index a8f6cfbec..e3e492e24 100644
--- a/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs
@@ -3,7 +3,7 @@ using System.ComponentModel;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Convert Pipe delimited string to array of type.
diff --git a/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs
index 1bebc49ec..579674f18 100644
--- a/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs
@@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Json Pipe delimited array converter factory.
diff --git a/MediaBrowser.Common/Json/Converters/JsonStringConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonStringConverter.cs
index 6cd980e48..1a7a8c4f5 100644
--- a/MediaBrowser.Common/Json/Converters/JsonStringConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonStringConverter.cs
@@ -4,7 +4,7 @@ using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Converter to allow the serializer to read strings.
diff --git a/MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonVersionConverter.cs
index 81c093c54..51ffec1cb 100644
--- a/MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonVersionConverter.cs
@@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace MediaBrowser.Common.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
{
/// <summary>
/// Converts a Version object or value to/from JSON.
diff --git a/MediaBrowser.Common/Json/JsonDefaults.cs b/src/Jellyfin.Extensions/Json/JsonDefaults.cs
index 405d6125f..f4ec91123 100644
--- a/MediaBrowser.Common/Json/JsonDefaults.cs
+++ b/src/Jellyfin.Extensions/Json/JsonDefaults.cs
@@ -1,8 +1,8 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
-namespace MediaBrowser.Common.Json
+namespace Jellyfin.Extensions.Json
{
/// <summary>
/// Helper class for having compatible JSON throughout the codebase.
diff --git a/MediaBrowser.Common/Extensions/ShuffleExtensions.cs b/src/Jellyfin.Extensions/ShuffleExtensions.cs
index 2604abf85..4e481983f 100644
--- a/MediaBrowser.Common/Extensions/ShuffleExtensions.cs
+++ b/src/Jellyfin.Extensions/ShuffleExtensions.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-namespace MediaBrowser.Common.Extensions
+namespace Jellyfin.Extensions
{
/// <summary>
/// Provides <c>Shuffle</c> extensions methods for <see cref="IList{T}" />.
diff --git a/MediaBrowser.Common/Extensions/SplitStringExtensions.cs b/src/Jellyfin.Extensions/SplitStringExtensions.cs
index 9c9108495..5fa5c0123 100644
--- a/MediaBrowser.Common/Extensions/SplitStringExtensions.cs
+++ b/src/Jellyfin.Extensions/SplitStringExtensions.cs
@@ -1,4 +1,4 @@
-/*
+/*
MIT License
Copyright (c) 2019 Gérald Barré
@@ -22,13 +22,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
-#pragma warning disable CS1591
-#pragma warning disable CA1034
+// TODO: remove when analyzer is fixed: https://github.com/dotnet/roslyn-analyzers/issues/5158
+#pragma warning disable CA1034 // Nested types should not be visible
+
using System;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
-namespace MediaBrowser.Common.Extensions
+namespace Jellyfin.Extensions
{
/// <summary>
/// Extension class for splitting lines without unnecessary allocations.
@@ -42,7 +43,7 @@ namespace MediaBrowser.Common.Extensions
/// <param name="separator">The separator to split on.</param>
/// <returns>The enumerator struct.</returns>
[Pure]
- public static SplitEnumerator SpanSplit(this string str, char separator) => new (str.AsSpan(), separator);
+ public static Enumerator SpanSplit(this string str, char separator) => new (str.AsSpan(), separator);
/// <summary>
/// Creates a new span split enumerator.
@@ -51,25 +52,44 @@ namespace MediaBrowser.Common.Extensions
/// <param name="separator">The separator to split on.</param>
/// <returns>The enumerator struct.</returns>
[Pure]
- public static SplitEnumerator Split(this ReadOnlySpan<char> str, char separator) => new (str, separator);
+ public static Enumerator Split(this ReadOnlySpan<char> str, char separator) => new (str, separator);
+ /// <summary>
+ /// Provides an enumerator for the substrings seperated by the separator.
+ /// </summary>
[StructLayout(LayoutKind.Auto)]
- public ref struct SplitEnumerator
+ public ref struct Enumerator
{
private readonly char _separator;
private ReadOnlySpan<char> _str;
- public SplitEnumerator(ReadOnlySpan<char> str, char separator)
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Enumerator"/> struct.
+ /// </summary>
+ /// <param name="str">The span to split.</param>
+ /// <param name="separator">The separator to split on.</param>
+ public Enumerator(ReadOnlySpan<char> str, char separator)
{
_str = str;
_separator = separator;
Current = default;
}
+ /// <summary>
+ /// Gets a reference to the item at the current position of the enumerator.
+ /// </summary>
public ReadOnlySpan<char> Current { get; private set; }
- public readonly SplitEnumerator GetEnumerator() => this;
+ /// <summary>
+ /// Returns <c>this</c>.
+ /// </summary>
+ /// <returns><c>this</c>.</returns>
+ public readonly Enumerator GetEnumerator() => this;
+ /// <summary>
+ /// Advances the enumerator to the next item.
+ /// </summary>
+ /// <returns><c>true</c> if there is a next element; otherwise <c>false</c>.</returns>
public bool MoveNext()
{
if (_str.Length == 0)
diff --git a/MediaBrowser.Common/Extensions/StreamExtensions.cs b/src/Jellyfin.Extensions/StreamExtensions.cs
index 5cbf57d98..9751d9d42 100644
--- a/MediaBrowser.Common/Extensions/StreamExtensions.cs
+++ b/src/Jellyfin.Extensions/StreamExtensions.cs
@@ -3,7 +3,7 @@ using System.IO;
using System.Linq;
using System.Text;
-namespace MediaBrowser.Common.Extensions
+namespace Jellyfin.Extensions
{
/// <summary>
/// Class BaseExtensions.
diff --git a/MediaBrowser.Common/Extensions/StringBuilderExtensions.cs b/src/Jellyfin.Extensions/StringBuilderExtensions.cs
index 75d654f23..02ff7cc1f 100644
--- a/MediaBrowser.Common/Extensions/StringBuilderExtensions.cs
+++ b/src/Jellyfin.Extensions/StringBuilderExtensions.cs
@@ -1,7 +1,7 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Text;
-namespace MediaBrowser.Common.Extensions
+namespace Jellyfin.Extensions
{
/// <summary>
/// Extension methods for the <see cref="StringBuilder"/> class.
diff --git a/src/Jellyfin.Extensions/StringExtensions.cs b/src/Jellyfin.Extensions/StringExtensions.cs
new file mode 100644
index 000000000..acc695ed2
--- /dev/null
+++ b/src/Jellyfin.Extensions/StringExtensions.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Jellyfin.Extensions
+{
+ /// <summary>
+ /// Provides extensions methods for <see cref="string" />.
+ /// </summary>
+ public static class StringExtensions
+ {
+ /// <summary>
+ /// Counts the number of occurrences of [needle] in the string.
+ /// </summary>
+ /// <param name="value">The haystack to search in.</param>
+ /// <param name="needle">The character to search for.</param>
+ /// <returns>The number of occurrences of the [needle] character.</returns>
+ public static int Count(this ReadOnlySpan<char> value, char needle)
+ {
+ var count = 0;
+ var length = value.Length;
+ for (var i = 0; i < length; i++)
+ {
+ if (value[i] == needle)
+ {
+ count++;
+ }
+ }
+
+ return count;
+ }
+ }
+}
diff --git a/tests/Jellyfin.Controller.Tests/AlphanumComparatorTests.cs b/tests/Jellyfin.Extensions.Tests/AlphanumericComparatorTests.cs
index 0adf098c3..7730841a1 100644
--- a/tests/Jellyfin.Controller.Tests/AlphanumComparatorTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/AlphanumericComparatorTests.cs
@@ -1,11 +1,10 @@
using System;
using System.Linq;
-using MediaBrowser.Controller.Sorting;
using Xunit;
-namespace Jellyfin.Controller.Tests
+namespace Jellyfin.Extensions.Tests
{
- public class AlphanumComparatorTests
+ public class AlphanumericComparatorTests
{
// InlineData is pre-sorted
[Theory]
@@ -20,10 +19,10 @@ namespace Jellyfin.Controller.Tests
[InlineData("12345678912345678912345678913234567891", "12345678912345678912345678913234567892")]
[InlineData("12345678912345678912345678913234567891a", "12345678912345678912345678913234567891a")]
[InlineData("12345678912345678912345678913234567891a", "12345678912345678912345678913234567891b")]
- public void AlphanumComparatorTest(params string?[] strings)
+ public void AlphanumericComparatorTest(params string?[] strings)
{
var copy = strings.Reverse().ToArray();
- Array.Sort(copy, new AlphanumComparator());
+ Array.Sort(copy, new AlphanumericComparator());
Assert.True(strings.SequenceEqual(copy));
}
}
diff --git a/tests/Jellyfin.Common.Tests/Extensions/CopyToExtensionsTests.cs b/tests/Jellyfin.Extensions.Tests/CopyToExtensionsTests.cs
index 9903409fa..6fdca4694 100644
--- a/tests/Jellyfin.Common.Tests/Extensions/CopyToExtensionsTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/CopyToExtensionsTests.cs
@@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
-using MediaBrowser.Common.Extensions;
using Xunit;
-namespace Jellyfin.Common.Tests.Extensions
+namespace Jellyfin.Extensions.Tests
{
public static class CopyToExtensionsTests
{
diff --git a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj
new file mode 100644
index 000000000..4b6dca377
--- /dev/null
+++ b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj
@@ -0,0 +1,38 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ <IsPackable>false</IsPackable>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
+ <AnalysisMode>AllEnabledByDefault</AnalysisMode>
+ <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
+ <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ <PrivateAssets>all</PrivateAssets>
+ </PackageReference>
+ <PackageReference Include="coverlet.collector" Version="1.3.0">
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ <PrivateAssets>all</PrivateAssets>
+ </PackageReference>
+ <PackageReference Include="FsCheck.Xunit" Version="2.15.3" />
+ </ItemGroup>
+
+ <!-- Code Analyzers -->
+ <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="../../MediaBrowser.Model/MediaBrowser.Model.csproj" />
+ <ProjectReference Include="../../src/Jellyfin.Extensions/Jellyfin.Extensions.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonBoolNumberTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs
index 7629d9912..d0e3e9456 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonBoolNumberTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs
@@ -1,11 +1,11 @@
-using System.Globalization;
+using System.Globalization;
using System.Text.Json;
using FsCheck;
using FsCheck.Xunit;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
using Xunit;
-namespace Jellyfin.Common.Tests.Json
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
public class JsonBoolNumberTests
{
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedArrayTests.cs
index ca300401d..f2ca2ff08 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedArrayTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedArrayTests.cs
@@ -1,11 +1,11 @@
-using System;
+using System;
using System.Text.Json;
using System.Text.Json.Serialization;
-using Jellyfin.Common.Tests.Models;
+using Jellyfin.Extensions.Tests.Json.Models;
using MediaBrowser.Model.Session;
using Xunit;
-namespace Jellyfin.Common.Tests.Json
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
public static class JsonCommaDelimitedArrayTests
{
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedIReadOnlyListTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs
index 34ad9bac7..92886dcd2 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonCommaDelimitedIReadOnlyListTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs
@@ -1,10 +1,10 @@
-using System.Text.Json;
+using System.Text.Json;
using System.Text.Json.Serialization;
-using Jellyfin.Common.Tests.Models;
+using Jellyfin.Extensions.Tests.Json.Models;
using MediaBrowser.Model.Session;
using Xunit;
-namespace Jellyfin.Common.Tests.Json
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
public static class JsonCommaDelimitedIReadOnlyListTests
{
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonGuidConverterTests.cs
index dbfad3c2f..8465d465a 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonGuidConverterTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonGuidConverterTests.cs
@@ -1,9 +1,9 @@
using System;
using System.Text.Json;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
using Xunit;
-namespace Jellyfin.Common.Tests.Json
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
public class JsonGuidConverterTests
{
diff --git a/tests/Jellyfin.Model.Tests/Entities/JsonLowerCaseConverterTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonLowerCaseConverterTests.cs
index 955d296cc..af9227de2 100644
--- a/tests/Jellyfin.Model.Tests/Entities/JsonLowerCaseConverterTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonLowerCaseConverterTests.cs
@@ -1,9 +1,10 @@
using System.Text.Json;
using System.Text.Json.Serialization;
+using Jellyfin.Extensions.Json.Converters;
using MediaBrowser.Model.Entities;
using Xunit;
-namespace Jellyfin.Model.Tests.Entities
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
public class JsonLowerCaseConverterTests
{
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonNullableGuidConverterTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonNullableGuidConverterTests.cs
index cb3b66c4c..b0dbc09e4 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonNullableGuidConverterTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonNullableGuidConverterTests.cs
@@ -1,9 +1,9 @@
using System;
using System.Text.Json;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
using Xunit;
-namespace Jellyfin.Common.Tests.Json
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
public class JsonNullableGuidConverterTests
{
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonStringConverterTests.cs
index 2b23c6705..655e07074 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonStringConverterTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonStringConverterTests.cs
@@ -1,8 +1,8 @@
-using System.Text.Json;
-using MediaBrowser.Common.Json.Converters;
+using System.Text.Json;
+using Jellyfin.Extensions.Json.Converters;
using Xunit;
-namespace Jellyfin.Common.Tests.Json
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
public class JsonStringConverterTests
{
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonVersionConverterTests.cs
index f2cefdbf8..5fbac7eab 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonVersionConverterTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonVersionConverterTests.cs
@@ -1,9 +1,9 @@
-using System;
+using System;
using System.Text.Json;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
using Xunit;
-namespace Jellyfin.Common.Tests.Json
+namespace Jellyfin.Extensions.Tests.Json.Converters
{
public class JsonVersionConverterTests
{
diff --git a/tests/Jellyfin.Common.Tests/Models/GenericBodyArrayModel.cs b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyArrayModel.cs
index 276e1bfbe..ef135278f 100644
--- a/tests/Jellyfin.Common.Tests/Models/GenericBodyArrayModel.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyArrayModel.cs
@@ -1,8 +1,8 @@
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
-namespace Jellyfin.Common.Tests.Models
+namespace Jellyfin.Extensions.Tests.Json.Models
{
/// <summary>
/// The generic body model.
diff --git a/tests/Jellyfin.Common.Tests/Models/GenericBodyIReadOnlyListModel.cs b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyListModel.cs
index 627454b25..8e7b5a35b 100644
--- a/tests/Jellyfin.Common.Tests/Models/GenericBodyIReadOnlyListModel.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyListModel.cs
@@ -1,8 +1,8 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Common.Json.Converters;
+using Jellyfin.Extensions.Json.Converters;
-namespace Jellyfin.Common.Tests.Models
+namespace Jellyfin.Extensions.Tests.Json.Models
{
/// <summary>
/// The generic body <c>IReadOnlyList</c> model.
diff --git a/tests/Jellyfin.Common.Tests/Extensions/ShuffleExtensionsTests.cs b/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs
index cbdbcf112..c72216d94 100644
--- a/tests/Jellyfin.Common.Tests/Extensions/ShuffleExtensionsTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs
@@ -1,8 +1,7 @@
using System;
-using MediaBrowser.Common.Extensions;
using Xunit;
-namespace Jellyfin.Common.Tests.Extensions
+namespace Jellyfin.Extensions.Tests
{
public static class ShuffleExtensionsTests
{
diff --git a/tests/Jellyfin.Controller.Tests/Extensions/StringExtensionsTests.cs b/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs
index 576c0a49b..d1aa2e476 100644
--- a/tests/Jellyfin.Controller.Tests/Extensions/StringExtensionsTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs
@@ -1,8 +1,7 @@
using System;
-using MediaBrowser.Controller.Extensions;
using Xunit;
-namespace Jellyfin.Controller.Extensions.Tests
+namespace Jellyfin.Extensions.Tests
{
public class StringExtensionsTests
{
diff --git a/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs
index 415682e85..45808375f 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs
@@ -1,7 +1,7 @@
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.MediaEncoding.Probing;
using Xunit;
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
index 98fbb00d5..d8089eea2 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
@@ -2,7 +2,7 @@ using System;
using System.Globalization;
using System.IO;
using System.Text.Json;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.MediaEncoding.Probing;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
diff --git a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs b/tests/Jellyfin.Providers.Tests/Omdb/JsonOmdbConverterTests.cs
index efe8063a0..25900bc09 100644
--- a/tests/Jellyfin.Common.Tests/Json/JsonOmdbConverterTests.cs
+++ b/tests/Jellyfin.Providers.Tests/Omdb/JsonOmdbConverterTests.cs
@@ -1,10 +1,9 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-using MediaBrowser.Common.Json.Converters;
using MediaBrowser.Providers.Plugins.Omdb;
using Xunit;
-namespace Jellyfin.Common.Tests.Json
+namespace Jellyfin.Providers.Tests.Omdb
{
public class JsonOmdbConverterTests
{
diff --git a/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs b/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs
index ea6838682..4ea05397d 100644
--- a/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs
@@ -7,7 +7,7 @@ using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Api.Models.StartupDtos;
using Jellyfin.Api.Models.UserDtos;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using Xunit;
namespace Jellyfin.Server.Integration.Tests
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs
index f5411dcb8..827365363 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs
@@ -5,7 +5,7 @@ using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Api.Models;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using Xunit;
namespace Jellyfin.Server.Integration.Tests.Controllers
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs
index 169a5a6c5..9c0fc72f6 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs
@@ -6,7 +6,7 @@ using System.Net.Mime;
using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Api.Models.StartupDtos;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using Xunit;
using Xunit.Priority;
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs
index 6584490de..8866ab53c 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs
@@ -8,7 +8,7 @@ using System.Net.Mime;
using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Api.Models.UserDtos;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Model.Dto;
using Xunit;
using Xunit.Priority;