Merge remote-tracking branch 'jellyfin/master' into nfo-tests

# Conflicts:
#	tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
#	tests/Jellyfin.XbmcMetadata.Tests/Parsers/SeriesNfoParserTests.cs
This commit is contained in:
David 2021-02-13 22:55:33 +01:00
commit fc7377fb9b
117 changed files with 1284 additions and 611 deletions

View File

@ -7,7 +7,7 @@ parameters:
default: "ubuntu-latest" default: "ubuntu-latest"
- name: DotNetSdkVersion - name: DotNetSdkVersion
type: string type: string
default: 5.0.100 default: 5.0.103
jobs: jobs:
- job: CompatibilityCheck - job: CompatibilityCheck

View File

@ -4,7 +4,7 @@
default: "ubuntu-latest" default: "ubuntu-latest"
- name: GeneratorVersion - name: GeneratorVersion
type: string type: string
default: "5.0.0-beta2" default: "5.0.1"
jobs: jobs:
- job: GenerateApiClients - job: GenerateApiClients

View File

@ -1,7 +1,7 @@
parameters: parameters:
LinuxImage: 'ubuntu-latest' LinuxImage: 'ubuntu-latest'
RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj' RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj'
DotNetSdkVersion: 5.0.100 DotNetSdkVersion: 5.0.103
jobs: jobs:
- job: Build - job: Build

View File

@ -10,7 +10,7 @@ parameters:
default: "tests/**/*Tests.csproj" default: "tests/**/*Tests.csproj"
- name: DotNetSdkVersion - name: DotNetSdkVersion
type: string type: string
default: 5.0.100 default: 5.0.103
jobs: jobs:
- job: Test - job: Test

View File

@ -6,7 +6,7 @@ variables:
- name: RestoreBuildProjects - name: RestoreBuildProjects
value: 'Jellyfin.Server/Jellyfin.Server.csproj' value: 'Jellyfin.Server/Jellyfin.Server.csproj'
- name: DotNetSdkVersion - name: DotNetSdkVersion
value: 5.0.100 value: 5.0.103
pr: pr:
autoCancel: true autoCancel: true

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification Identification = new DeviceIdentification
{ {
FriendlyName = @"KDL-\d{2}[EHLNPB]X\d[01]\d.*", FriendlyName = @"KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*",
Manufacturer = "Sony", Manufacturer = "Sony",
Headers = new[] Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo new HttpHeaderInfo
{ {
Name = "X-AV-Client-Info", Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}[EHLNPB]X\d[01]\d.*", Value = @".*KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*",
Match = HeaderMatchType.Regex Match = HeaderMatchType.Regex
} }
} }

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification Identification = new DeviceIdentification
{ {
FriendlyName = @"KDL-\d{2}([A-Z]X\d2\d|CX400).*", FriendlyName = @"KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*",
Manufacturer = "Sony", Manufacturer = "Sony",
Headers = new[] Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo new HttpHeaderInfo
{ {
Name = "X-AV-Client-Info", Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}([A-Z]X\d2\d|CX400).*", Value = @".*KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*",
Match = HeaderMatchType.Regex Match = HeaderMatchType.Regex
} }
} }

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification Identification = new DeviceIdentification
{ {
FriendlyName = @"KDL-\d{2}[A-Z]X\d5(\d|G).*", FriendlyName = @"KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*",
Manufacturer = "Sony", Manufacturer = "Sony",
Headers = new[] Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo new HttpHeaderInfo
{ {
Name = "X-AV-Client-Info", Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}[A-Z]X\d5(\d|G).*", Value = @".*KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*",
Match = HeaderMatchType.Regex Match = HeaderMatchType.Regex
} }
} }

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification Identification = new DeviceIdentification
{ {
FriendlyName = @"KDL-\d{2}[WR][5689]\d{2}A.*", FriendlyName = @"KDL-[0-9]{2}[WR][5689][0-9]{2}A.*",
Manufacturer = "Sony", Manufacturer = "Sony",
Headers = new[] Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo new HttpHeaderInfo
{ {
Name = "X-AV-Client-Info", Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}[WR][5689]\d{2}A.*", Value = @".*KDL-[0-9]{2}[WR][5689][0-9]{2}A.*",
Match = HeaderMatchType.Regex Match = HeaderMatchType.Regex
} }
} }

View File

@ -13,7 +13,7 @@ namespace Emby.Dlna.Profiles
Identification = new DeviceIdentification Identification = new DeviceIdentification
{ {
FriendlyName = @"(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*", FriendlyName = @"(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*",
Manufacturer = "Sony", Manufacturer = "Sony",
Headers = new[] Headers = new[]
@ -21,7 +21,7 @@ namespace Emby.Dlna.Profiles
new HttpHeaderInfo new HttpHeaderInfo
{ {
Name = "X-AV-Client-Info", Name = "X-AV-Client-Info",
Value = @".*(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*", Value = @".*(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*",
Match = HeaderMatchType.Regex Match = HeaderMatchType.Regex
} }
} }

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2010)</Name> <Name>Sony Bravia (2010)</Name>
<Identification> <Identification>
<FriendlyName>KDL-\d{2}[EHLNPB]X\d[01]\d.*</FriendlyName> <FriendlyName>KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*</FriendlyName>
<Manufacturer>Sony</Manufacturer> <Manufacturer>Sony</Manufacturer>
<Headers> <Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[EHLNPB]X\d[01]\d.*" match="Regex" /> <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*" match="Regex" />
</Headers> </Headers>
</Identification> </Identification>
<Manufacturer>Microsoft Corporation</Manufacturer> <Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2011)</Name> <Name>Sony Bravia (2011)</Name>
<Identification> <Identification>
<FriendlyName>KDL-\d{2}([A-Z]X\d2\d|CX400).*</FriendlyName> <FriendlyName>KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*</FriendlyName>
<Manufacturer>Sony</Manufacturer> <Manufacturer>Sony</Manufacturer>
<Headers> <Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}([A-Z]X\d2\d|CX400).*" match="Regex" /> <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*" match="Regex" />
</Headers> </Headers>
</Identification> </Identification>
<Manufacturer>Microsoft Corporation</Manufacturer> <Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2012)</Name> <Name>Sony Bravia (2012)</Name>
<Identification> <Identification>
<FriendlyName>KDL-\d{2}[A-Z]X\d5(\d|G).*</FriendlyName> <FriendlyName>KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*</FriendlyName>
<Manufacturer>Sony</Manufacturer> <Manufacturer>Sony</Manufacturer>
<Headers> <Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[A-Z]X\d5(\d|G).*" match="Regex" /> <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*" match="Regex" />
</Headers> </Headers>
</Identification> </Identification>
<Manufacturer>Microsoft Corporation</Manufacturer> <Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2013)</Name> <Name>Sony Bravia (2013)</Name>
<Identification> <Identification>
<FriendlyName>KDL-\d{2}[WR][5689]\d{2}A.*</FriendlyName> <FriendlyName>KDL-[0-9]{2}[WR][5689][0-9]{2}A.*</FriendlyName>
<Manufacturer>Sony</Manufacturer> <Manufacturer>Sony</Manufacturer>
<Headers> <Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[WR][5689]\d{2}A.*" match="Regex" /> <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-[0-9]{2}[WR][5689][0-9]{2}A.*" match="Regex" />
</Headers> </Headers>
</Identification> </Identification>
<Manufacturer>Microsoft Corporation</Manufacturer> <Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -3,10 +3,10 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Sony Bravia (2014)</Name> <Name>Sony Bravia (2014)</Name>
<Identification> <Identification>
<FriendlyName>(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*</FriendlyName> <FriendlyName>(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*</FriendlyName>
<Manufacturer>Sony</Manufacturer> <Manufacturer>Sony</Manufacturer>
<Headers> <Headers>
<HttpHeaderInfo name="X-AV-Client-Info" value=".*(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*" match="Regex" /> <HttpHeaderInfo name="X-AV-Client-Info" value=".*(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*" match="Regex" />
</Headers> </Headers>
</Identification> </Identification>
<Manufacturer>Microsoft Corporation</Manufacturer> <Manufacturer>Microsoft Corporation</Manufacturer>

View File

@ -284,7 +284,7 @@ namespace Emby.Naming.Common
// Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names // Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names
// [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the series name // [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the series name
new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[\s_]*-[\s_]*(?<epnumber>\d+).*$") new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+).*$")
{ {
IsNamed = true IsNamed = true
}, },
@ -588,7 +588,7 @@ namespace Emby.Naming.Common
AudioBookNamesExpressions = new[] AudioBookNamesExpressions = new[]
{ {
// Detect year usually in brackets after name Batman (2020) // Detect year usually in brackets after name Batman (2020)
@"^(?<name>.+?)\s*\(\s*(?<year>\d{4})\s*\)\s*$", @"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
@"^\s*(?<name>[^ ].*?)\s*$" @"^\s*(?<name>[^ ].*?)\s*$"
}; };

View File

@ -33,7 +33,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Naming</PackageId> <PackageId>Jellyfin.Naming</PackageId>
<VersionPrefix>10.7.0</VersionPrefix> <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>

View File

@ -249,7 +249,7 @@ namespace Emby.Server.Implementations.Dto
var activeRecording = liveTvManager.GetActiveRecordingInfo(item.Path); var activeRecording = liveTvManager.GetActiveRecordingInfo(item.Path);
if (activeRecording != null) if (activeRecording != null)
{ {
dto.Type = "Recording"; dto.Type = BaseItemKind.Recording;
dto.CanDownload = false; dto.CanDownload = false;
dto.RunTimeTicks = null; dto.RunTimeTicks = null;
@ -904,7 +904,7 @@ namespace Emby.Server.Implementations.Dto
} }
} }
dto.Type = item.GetClientTypeName(); dto.Type = item.GetBaseItemKind();
if ((item.CommunityRating ?? 0) > 0) if ((item.CommunityRating ?? 0) > 0)
{ {
dto.CommunityRating = item.CommunityRating; dto.CommunityRating = item.CommunityRating;

View File

@ -5,6 +5,7 @@ using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Net; using System.Net;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -138,7 +139,7 @@ namespace Emby.Server.Implementations.HttpServer
writer.Advance(bytesRead); writer.Advance(bytesRead);
// Make the data available to the PipeReader // Make the data available to the PipeReader
FlushResult flushResult = await writer.FlushAsync().ConfigureAwait(false); FlushResult flushResult = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
if (flushResult.IsCompleted) if (flushResult.IsCompleted)
{ {
// The PipeReader stopped reading // The PipeReader stopped reading
@ -181,32 +182,16 @@ namespace Emby.Server.Implementations.HttpServer
} }
WebSocketMessage<object>? stub; WebSocketMessage<object>? stub;
long bytesConsumed = 0;
try try
{ {
stub = DeserializeWebSocketMessage(buffer, out bytesConsumed);
if (buffer.IsSingleSegment)
{
stub = JsonSerializer.Deserialize<WebSocketMessage<object>>(buffer.FirstSpan, _jsonOptions);
}
else
{
var buf = ArrayPool<byte>.Shared.Rent(Convert.ToInt32(buffer.Length));
try
{
buffer.CopyTo(buf);
stub = JsonSerializer.Deserialize<WebSocketMessage<object>>(buf, _jsonOptions);
}
finally
{
ArrayPool<byte>.Shared.Return(buf);
}
}
} }
catch (JsonException ex) catch (JsonException ex)
{ {
// Tell the PipeReader how much of the buffer we have consumed // Tell the PipeReader how much of the buffer we have consumed
reader.AdvanceTo(buffer.End); reader.AdvanceTo(buffer.End);
_logger.LogError(ex, "Error processing web socket message"); _logger.LogError(ex, "Error processing web socket message: {Data}", Encoding.UTF8.GetString(buffer));
return; return;
} }
@ -217,27 +202,34 @@ namespace Emby.Server.Implementations.HttpServer
} }
// Tell the PipeReader how much of the buffer we have consumed // Tell the PipeReader how much of the buffer we have consumed
reader.AdvanceTo(buffer.End); reader.AdvanceTo(buffer.GetPosition(bytesConsumed));
_logger.LogDebug("WS {IP} received message: {@Message}", RemoteEndPoint, stub); _logger.LogDebug("WS {IP} received message: {@Message}", RemoteEndPoint, stub);
var info = new WebSocketMessageInfo if (stub.MessageType == SessionMessageType.KeepAlive)
{
MessageType = stub.MessageType,
Data = stub.Data?.ToString(), // Data can be null
Connection = this
};
if (info.MessageType == SessionMessageType.KeepAlive)
{ {
await SendKeepAliveResponse().ConfigureAwait(false); await SendKeepAliveResponse().ConfigureAwait(false);
} }
else else
{ {
await OnReceive(info).ConfigureAwait(false); await OnReceive(
new WebSocketMessageInfo
{
MessageType = stub.MessageType,
Data = stub.Data?.ToString(), // Data can be null
Connection = this
}).ConfigureAwait(false);
} }
} }
internal WebSocketMessage<object>? DeserializeWebSocketMessage(ReadOnlySequence<byte> bytes, out long bytesConsumed)
{
var jsonReader = new Utf8JsonReader(bytes);
var ret = JsonSerializer.Deserialize<WebSocketMessage<object>>(ref jsonReader, _jsonOptions);
bytesConsumed = jsonReader.BytesConsumed;
return ret;
}
private Task SendKeepAliveResponse() private Task SendKeepAliveResponse()
{ {
LastKeepAliveDate = DateTime.UtcNow; LastKeepAliveDate = DateTime.UtcNow;

View File

@ -79,11 +79,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
return new MusicArtist(); return new MusicArtist();
} }
if (_config.Configuration.EnableSimpleArtistDetection)
{
return null;
}
// Avoid mis-identifying top folders // Avoid mis-identifying top folders
if (args.Parent.IsRoot) if (args.Parent.IsRoot)
{ {

View File

@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public LegacyHdHomerunChannelCommands(string url) public LegacyHdHomerunChannelCommands(string url)
{ {
// parse url for channel and program // parse url for channel and program
var regExp = new Regex(@"\/ch(\d+)-?(\d*)"); var regExp = new Regex(@"\/ch([0-9]+)-?([0-9]*)");
var match = regExp.Match(url); var match = regExp.Match(url);
if (match.Success) if (match.Success)
{ {

View File

@ -55,26 +55,26 @@
"NotificationOptionPluginInstalled": "Приставката е инсталирана", "NotificationOptionPluginInstalled": "Приставката е инсталирана",
"NotificationOptionPluginUninstalled": "Приставката е деинсталирана", "NotificationOptionPluginUninstalled": "Приставката е деинсталирана",
"NotificationOptionPluginUpdateInstalled": "Обновлението на приставката е инсталирано", "NotificationOptionPluginUpdateInstalled": "Обновлението на приставката е инсталирано",
"NotificationOptionServerRestartRequired": "Нужно е повторно пускане на сървъра", "NotificationOptionServerRestartRequired": "Сървърът трябва да се рестартира",
"NotificationOptionTaskFailed": "Грешка в планирана задача", "NotificationOptionTaskFailed": "Грешка в планирана задача",
"NotificationOptionUserLockedOut": "Потребителя е заключен", "NotificationOptionUserLockedOut": "Потребителят е заключен",
"NotificationOptionVideoPlayback": "Възпроизвеждането на видео започна", "NotificationOptionVideoPlayback": "Възпроизвеждането на видео започна",
"NotificationOptionVideoPlaybackStopped": "Възпроизвеждането на видео е спряно", "NotificationOptionVideoPlaybackStopped": "Възпроизвеждането на видео е спряно",
"Photos": "Снимки", "Photos": "Снимки",
"Playlists": "Списъци", "Playlists": "Списъци",
"Plugin": "Приставка", "Plugin": "Приставка",
"PluginInstalledWithName": "{0} е инсталирано", "PluginInstalledWithName": "{0} е инсталиранa",
"PluginUninstalledWithName": "{0} е деинсталирано", "PluginUninstalledWithName": "{0} е деинсталиранa",
"PluginUpdatedWithName": "{0} е обновено", "PluginUpdatedWithName": "{0} е обновенa",
"ProviderValue": "Доставчик: {0}", "ProviderValue": "Доставчик: {0}",
"ScheduledTaskFailedWithName": "{0} се провали", "ScheduledTaskFailedWithName": "{0} се провали",
"ScheduledTaskStartedWithName": "{0} започна", "ScheduledTaskStartedWithName": "{0} започна",
"ServerNameNeedsToBeRestarted": "{0} е нужно да се рестартира", "ServerNameNeedsToBeRestarted": "{0} трябва да се рестартира",
"Shows": "Сериали", "Shows": "Сериали",
"Songs": "Песни", "Songs": "Песни",
"StartupEmbyServerIsLoading": "Сървърът зарежда. Моля, опитайте отново след малко.", "StartupEmbyServerIsLoading": "Сървърът зарежда. Моля, опитайте отново след малко.",
"SubtitleDownloadFailureForItem": "Неуспешно изтегляне на субтитри за {0}", "SubtitleDownloadFailureForItem": "Неуспешно изтегляне на субтитри за {0}",
"SubtitleDownloadFailureFromForItem": "Поднадписите за {1} от {0} не можаха да се изтеглят", "SubtitleDownloadFailureFromForItem": "Субтитрите за {1} от {0} не можаха да бъдат изтеглени",
"Sync": "Синхронизиране", "Sync": "Синхронизиране",
"System": "Система", "System": "Система",
"TvShows": "Телевизионни сериали", "TvShows": "Телевизионни сериали",
@ -92,12 +92,12 @@
"ValueHasBeenAddedToLibrary": "{0} беше добавен във Вашата библиотека", "ValueHasBeenAddedToLibrary": "{0} беше добавен във Вашата библиотека",
"ValueSpecialEpisodeName": "Специални - {0}", "ValueSpecialEpisodeName": "Специални - {0}",
"VersionNumber": "Версия {0}", "VersionNumber": "Версия {0}",
"TaskDownloadMissingSubtitlesDescription": "Търси Интернет за липсващи поднадписи, на база конфигурацията за мета-данни.", "TaskDownloadMissingSubtitlesDescription": "Търси Интернет за липсващи субтитри, на база конфигурацията за мета-данни.",
"TaskDownloadMissingSubtitles": "Изтегляне на липсващи поднадписи", "TaskDownloadMissingSubtitles": "Изтегляне на липсващи субтитри",
"TaskRefreshChannelsDescription": "Обновява информацията за интернет канала.", "TaskRefreshChannelsDescription": "Обновява информацията за интернет канала.",
"TaskRefreshChannels": "Обновяване на Канали", "TaskRefreshChannels": "Обновяване на Канали",
"TaskCleanTranscodeDescription": "Изтрива прекодирани файлове по-стари от един ден.", "TaskCleanTranscodeDescription": "Изтрива транскодирани файлове по-стари от един ден.",
"TaskCleanTranscode": "Изчиства директорията за прекодиране", "TaskCleanTranscode": "Изчиства директорията за транскодиране",
"TaskUpdatePluginsDescription": "Изтегля и инсталира актуализации за добавките, които са настроени за автоматична актуализация.", "TaskUpdatePluginsDescription": "Изтегля и инсталира актуализации за добавките, които са настроени за автоматична актуализация.",
"TaskUpdatePlugins": "Актуализира добавките", "TaskUpdatePlugins": "Актуализира добавките",
"TaskRefreshPeopleDescription": "Актуализира мета-данните за артистите и режисьорите за Вашата медийна библиотека.", "TaskRefreshPeopleDescription": "Актуализира мета-данните за артистите и режисьорите за Вашата медийна библиотека.",

View File

@ -0,0 +1,26 @@
{
"NotificationOptionInstallationFailed": "Instalada fiasko",
"NotificationOptionAudioPlaybackStopped": "Sono de ludado haltis",
"NotificationOptionAudioPlayback": "Ludado de sono startis",
"NameSeasonUnknown": "Sezono Nekonata",
"NameSeasonNumber": "Sezono {0}",
"NameInstallFailed": "{0} instalado fiaskis",
"Music": "Muziko",
"Movies": "Filmoj",
"ItemRemovedWithName": "{0} forigis el la biblioteko",
"ItemAddedWithName": "{0} aldonis al la biblioteko",
"HeaderLiveTV": "Viva Televido",
"HeaderContinueWatching": "Daŭrigi Spektado",
"HeaderAlbumArtists": "Artistoj de Albumo",
"Folders": "Dosierujoj",
"DeviceOnlineWithName": "{0} estas konektita",
"Default": "Defaŭlte",
"Collections": "Kolektoj",
"ChapterNameValue": "Ĉapitro {0}",
"Channels": "Kanaloj",
"Books": "Libroj",
"Artists": "Artistoj",
"Application": "Aplikaĵo",
"AppDeviceValues": "Aplikaĵo: {0}, Aparato: {1}",
"Albums": "Albumoj"
}

View File

@ -1,121 +1,121 @@
{ {
"HeaderLiveTV": "Live-TV", "HeaderLiveTV": "Live TV",
"NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa.", "NewVersionIsAvailable": "Uusi versio Jellyfin-palvelimesta on ladattavissa.",
"NameSeasonUnknown": "Tuntematon kausi", "NameSeasonUnknown": "Tuntematon kausi",
"NameSeasonNumber": "Kausi {0}", "NameSeasonNumber": "Kausi {0}",
"NameInstallFailed": "{0} asennus epäonnistui", "NameInstallFailed": "{0} asennus epäonnistui",
"MusicVideos": "Musiikkivideot", "MusicVideos": "Musiikkivideot",
"Music": "Musiikki", "Music": "Musiikki",
"Movies": "Elokuvat", "Movies": "Elokuvat",
"MixedContent": "Sekoitettu sisältö", "MixedContent": "Sekalainen sisältö",
"MessageServerConfigurationUpdated": "Palvelimen asetukset on päivitetty", "MessageServerConfigurationUpdated": "Palvelimen asetukset on päivitetty",
"MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusryhmä {0} on päivitetty", "MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusten osio {0} on päivitetty",
"MessageApplicationUpdatedTo": "Jellyfin palvelin on päivitetty versioon {0}", "MessageApplicationUpdatedTo": "Jellyfin-palvelin on päivitetty versioon {0}",
"MessageApplicationUpdated": "Jellyfin palvelin on päivitetty", "MessageApplicationUpdated": "Jellyfin-palvelin on päivitetty",
"Latest": "Uusimmat", "Latest": "Viimeisimmät",
"LabelRunningTimeValue": "Toiston kesto: {0}", "LabelRunningTimeValue": "Kesto: {0}",
"LabelIpAddressValue": "IP-osoite: {0}", "LabelIpAddressValue": "IP-osoite: {0}",
"ItemRemovedWithName": "{0} poistettiin kirjastosta", "ItemRemovedWithName": "{0} poistettiin kirjastosta",
"ItemAddedWithName": "{0} lisättiin kirjastoon", "ItemAddedWithName": "{0} lisättiin kirjastoon",
"Inherit": "Periytyä", "Inherit": "Peri",
"HomeVideos": "Kotivideot", "HomeVideos": "Kotivideot",
"HeaderRecordingGroups": "Tallennusryhmät", "HeaderRecordingGroups": "Tallennusryhmät",
"HeaderNextUp": "Seuraavaksi", "HeaderNextUp": "Seuraavaksi",
"HeaderFavoriteSongs": "Suosikkikappaleet", "HeaderFavoriteSongs": "Suosikkikappaleet",
"HeaderFavoriteShows": "Suosikkisarjat", "HeaderFavoriteShows": "Suosikkisarjat",
"HeaderFavoriteEpisodes": "Suosikkijaksot", "HeaderFavoriteEpisodes": "Suosikkijaksot",
"HeaderFavoriteArtists": "Suosikkiartistit", "HeaderFavoriteArtists": "Suosikkiesittäjät",
"HeaderFavoriteAlbums": "Suosikkialbumit", "HeaderFavoriteAlbums": "Suosikkialbumit",
"HeaderContinueWatching": "Jatka katsomista", "HeaderContinueWatching": "Jatka katselua",
"HeaderAlbumArtists": "Albumin artistit", "HeaderAlbumArtists": "Albumin esittäjät",
"Genres": "Tyylilajit", "Genres": "Tyylilajit",
"Folders": "Kansiot", "Folders": "Kansiot",
"Favorites": "Suosikit", "Favorites": "Suosikit",
"FailedLoginAttemptWithUserName": "Kirjautuminen epäonnistui kohteesta {0}", "FailedLoginAttemptWithUserName": "Epäonnistunut kirjautumisyritys lähteestä \"{0}\"",
"DeviceOnlineWithName": "{0} on yhdistetty", "DeviceOnlineWithName": "{0} on yhdistetty",
"DeviceOfflineWithName": "{0} yhteys on katkaistu", "DeviceOfflineWithName": "{0} on katkaissut yhteyden",
"Collections": "Kokoelmat", "Collections": "Kokoelmat",
"ChapterNameValue": "Jakso: {0}", "ChapterNameValue": "Kappale {0}",
"Channels": "Kanavat", "Channels": "Kanavat",
"CameraImageUploadedFrom": "Uusi kamerakuva on ladattu {0}", "CameraImageUploadedFrom": "Uusi kameran kuva on sirretty lähteestä {0}",
"Books": "Kirjat", "Books": "Kirjat",
"AuthenticationSucceededWithUserName": "Käyttäjän {0} todennus onnistui", "AuthenticationSucceededWithUserName": "{0} on todennettu",
"Artists": "Artistit", "Artists": "Esittäjät",
"Application": "Sovellus", "Application": "Sovellus",
"AppDeviceValues": "Sovellus: {0}, Laite: {1}", "AppDeviceValues": "Sovellus: {0}, Laite: {1}",
"Albums": "Albumit", "Albums": "Albumit",
"User": "Käyttäjä", "User": "Käyttäjä",
"System": "Järjestelmä", "System": "Järjestelmä",
"ScheduledTaskFailedWithName": "{0} epäonnistui", "ScheduledTaskFailedWithName": "{0} epäonnistui",
"PluginUpdatedWithName": "{0} päivitetty", "PluginUpdatedWithName": "{0} päivitettiin",
"PluginInstalledWithName": "{0} asennettu", "PluginInstalledWithName": "{0} asennettiin",
"Photos": "Kuvat", "Photos": "Valokuvat",
"ScheduledTaskStartedWithName": "{0} aloitettu", "ScheduledTaskStartedWithName": "\"{0}\" käynnistetty",
"PluginUninstalledWithName": "{0} poistettu", "PluginUninstalledWithName": "{0} poistettiin",
"Playlists": "Soittolistat", "Playlists": "Soittolistat",
"VersionNumber": "Versio {0}", "VersionNumber": "Versio {0}",
"ValueSpecialEpisodeName": "Erikois - {0}", "ValueSpecialEpisodeName": "Erikoisjakso - {0}",
"ValueHasBeenAddedToLibrary": "{0} lisättiin mediakirjastoon", "ValueHasBeenAddedToLibrary": "\"{0}\" on lisätty mediakirjastoon",
"UserStoppedPlayingItemWithValues": "{0} toistaminen valmistui {1} laitteella {2}", "UserStoppedPlayingItemWithValues": "{0} lopetti kohteen \"{1}\" toiston sijainnissa \"{2}\"",
"UserStartedPlayingItemWithValues": "{0} toistaa {1} laitteella {2}", "UserStartedPlayingItemWithValues": "{0} toistaa kohdetta \"{1}\" sijainnissa \"{2}\"",
"UserPolicyUpdatedWithName": "Käyttöoikeudet päivitetty käyttäjälle {0}", "UserPolicyUpdatedWithName": "Käyttäjän {0} käyttöoikeudet on päivitetty",
"UserPasswordChangedWithName": "Salasana vaihdettu käyttäjälle {0}", "UserPasswordChangedWithName": "Käyttäjän {0} salasana on vaihdettu",
"UserOnlineFromDevice": "{0} on paikalla osoitteesta {1}", "UserOnlineFromDevice": "{0} on yhdistänyt sijainnista \"{1}\"",
"UserOfflineFromDevice": "{0} yhteys katkaistu kohteesta {1}", "UserOfflineFromDevice": "{0} on katkaissut yhteyden sijainnista \"{1}\"",
"UserLockedOutWithName": "Käyttäjä {0} lukittu", "UserLockedOutWithName": "Käyttäjä {0} on lukittu",
"UserDownloadingItemWithValues": "{0} lataa {1}", "UserDownloadingItemWithValues": "{0} lataa kohdetta \"{1}\"",
"UserDeletedWithName": "Käyttäjä {0} poistettu", "UserDeletedWithName": "Käyttäjä {0} on poistettu",
"UserCreatedWithName": "Käyttäjä {0} luotu", "UserCreatedWithName": "Käyttäjä {0} on luotu",
"TvShows": "TV-ohjelmat", "TvShows": "Sarjat",
"Sync": "Synkronoi", "Sync": "Synkronointi",
"SubtitleDownloadFailureFromForItem": "Tekstitystä ei voitu ladata osoitteesta {0} kohteelle {1}", "SubtitleDownloadFailureFromForItem": "Tekstityksen lataus lähteestä \"{0}\" kohteelle \"{1}\" epäonnistui",
"StartupEmbyServerIsLoading": "Jellyfin palvelin latautuu. Yritä hetken kuluttua uudelleen.", "StartupEmbyServerIsLoading": "Jellyfin-palvelin latautuu. Yritä hetken kuluttua uudelleen.",
"Songs": "Kappaleet", "Songs": "Kappaleet",
"Shows": "Ohjelmat", "Shows": "Sarjat",
"ServerNameNeedsToBeRestarted": "{0} on käynnistettävä uudelleen", "ServerNameNeedsToBeRestarted": "\"{0}\" on käynnistettävä uudelleen",
"ProviderValue": "Tarjoaja: {0}", "ProviderValue": "Lähde: {0}",
"Plugin": "Liitännäinen", "Plugin": "Laajennus",
"NotificationOptionVideoPlaybackStopped": "Videon toisto pysäytetty", "NotificationOptionVideoPlaybackStopped": "Videon toisto lopetettu",
"NotificationOptionVideoPlayback": "Videota toistetaan", "NotificationOptionVideoPlayback": "Videon toisto aloitettu",
"NotificationOptionUserLockedOut": "Käyttäjä kirjautui ulos", "NotificationOptionUserLockedOut": "Käyttäjä on lukittu",
"NotificationOptionTaskFailed": "Ajastettu tehtävä epäonnistui", "NotificationOptionTaskFailed": "Ajoitettu tehtävä epäonnistui",
"NotificationOptionServerRestartRequired": "Palvelin on käynnistettävä uudelleen", "NotificationOptionServerRestartRequired": "Tarvitaan palvelimen uudelleenkäynnistys",
"NotificationOptionPluginUpdateInstalled": "Liitännäinen päivitetty", "NotificationOptionPluginUpdateInstalled": "Laajennus on päivitetty",
"NotificationOptionPluginUninstalled": "Liitännäinen poistettu", "NotificationOptionPluginUninstalled": "Laajennus on poistettu",
"NotificationOptionPluginInstalled": "Liitännäinen asennettu", "NotificationOptionPluginInstalled": "Laajennus on asennettu",
"NotificationOptionPluginError": "Ongelma liitännäisessä", "NotificationOptionPluginError": "Laajennuksen virhe",
"NotificationOptionNewLibraryContent": "Uutta sisältöä lisätty", "NotificationOptionNewLibraryContent": "Sisältöä on lisätty",
"NotificationOptionInstallationFailed": "Asennus epäonnistui", "NotificationOptionInstallationFailed": "Asennus epäonnistui",
"NotificationOptionCameraImageUploaded": "Kameran kuva ladattu", "NotificationOptionCameraImageUploaded": "Kameran kuva on tallennettu",
"NotificationOptionAudioPlaybackStopped": "Äänen toisto lopetettu", "NotificationOptionAudioPlaybackStopped": "Äänen toisto lopetettu",
"NotificationOptionAudioPlayback": "Toistetaan ääntä", "NotificationOptionAudioPlayback": "Äänen toisto aloitettu",
"NotificationOptionApplicationUpdateInstalled": "Sovelluspäivitys asennettu", "NotificationOptionApplicationUpdateInstalled": "Sovelluspäivitys asennettiin",
"NotificationOptionApplicationUpdateAvailable": "Ohjelmistopäivitys saatavilla", "NotificationOptionApplicationUpdateAvailable": "Sovelluspäivitys on saatavilla",
"TasksMaintenanceCategory": "Ylläpito", "TasksMaintenanceCategory": "Ylläpito",
"TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä videon metadatatietojen pohjalta.", "TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä määritettyjen metatietoasetusten mukaisesti.",
"TaskDownloadMissingSubtitles": "Lataa puuttuvat tekstitykset", "TaskDownloadMissingSubtitles": "Lataa puuttuvat tekstitykset",
"TaskRefreshChannelsDescription": "Päivittää internet-kanavien tiedot.", "TaskRefreshChannelsDescription": "Päivittää internet-kanavien tiedot.",
"TaskRefreshChannels": "Päivitä kanavat", "TaskRefreshChannels": "Päivitä kanavat",
"TaskCleanTranscodeDescription": "Poistaa transkoodatut tiedostot jotka ovat yli päivän vanhoja.", "TaskCleanTranscodeDescription": "Poistaa päivää vanhemmat transkoodaustiedostot.",
"TaskCleanTranscode": "Puhdista transkoodaushakemisto", "TaskCleanTranscode": "Puhdista transkoodauskansio",
"TaskUpdatePluginsDescription": "Lataa ja asentaa päivitykset liitännäisille jotka on asetettu päivittymään automaattisesti.", "TaskUpdatePluginsDescription": "Lataa ja asentaa päivitykset laajennuksille, jotka on määritetty päivittymään automaattisesti.",
"TaskUpdatePlugins": "Päivitä liitännäiset", "TaskUpdatePlugins": "Päivitä laajennukset",
"TaskRefreshPeopleDescription": "Päivittää näyttelijöiden ja ohjaajien mediatiedot kirjastossasi.", "TaskRefreshPeopleDescription": "Päivittää mediakirjaston näyttelijöiden ja ohjaajien metatiedot.",
"TaskRefreshPeople": "Päivitä henkilöt", "TaskRefreshPeople": "Päivitä henkilöt",
"TaskCleanLogsDescription": "Poistaa lokitiedostot jotka ovat yli {0} päivää vanhoja.", "TaskCleanLogsDescription": "Poistaa {0} päivää vanhemmat lokitiedostot.",
"TaskCleanLogs": "Puhdista lokihakemisto", "TaskCleanLogs": "Siivoa lokikansio",
"TaskRefreshLibraryDescription": "Skannaa mediakirjastosi uudet tiedostot ja päivittää metatiedot.", "TaskRefreshLibraryDescription": "Tarkastaa mediakirjastosi sisällön uusien tiedostojen varalta ja päivittää metatiedot.",
"TaskRefreshLibrary": "Skannaa mediakirjasto", "TaskRefreshLibrary": "Päivitä mediakirjasto",
"TaskRefreshChapterImagesDescription": "Luo pienoiskuvat videoille joissa on jaksoja.", "TaskRefreshChapterImagesDescription": "Luo esikatselukuvat videoille, jotka sisältävät kappalejaon.",
"TaskRefreshChapterImages": "Pura jakson kuvat", "TaskRefreshChapterImages": "Pura kappalejaon kuvat",
"TaskCleanCacheDescription": "Poistaa järjestelmälle tarpeettomat väliaikaistiedostot.", "TaskCleanCacheDescription": "Poistaa tarpeettomiksi jääneet väliaikaistiedostot.",
"TaskCleanCache": "Tyhjennä välimuisti-hakemisto", "TaskCleanCache": "Tyhjennä välimuistikansio",
"TasksChannelsCategory": "Internet kanavat", "TasksChannelsCategory": "Internet-kanavat",
"TasksApplicationCategory": "Sovellus", "TasksApplicationCategory": "Sovellus",
"TasksLibraryCategory": "Kirjasto", "TasksLibraryCategory": "Kirjasto",
"Forced": "Pakotettu", "Forced": "Pakotettu",
"Default": "Oletus", "Default": "Oletus",
"TaskCleanActivityLogDescription": "Poistaa määritettyä vanhemmat tapahtumat aktiviteettilokista.", "TaskCleanActivityLogDescription": "Poistaa määritettyä ikää vanhemmat tapahtumat toimintahistoriasta.",
"TaskCleanActivityLog": "Tyhjennä aktiviteettiloki", "TaskCleanActivityLog": "Tyhjennä toimintahistoria",
"Undefined": "Määrittelemätön" "Undefined": "Määrittelemätön"
} }

View File

@ -1,5 +1,5 @@
{ {
"Albums": "संग्रह", "Albums": "एल्बम",
"HeaderRecordingGroups": "रिकॉर्डिंग समूह", "HeaderRecordingGroups": "रिकॉर्डिंग समूह",
"HeaderNextUp": "इसके बाद", "HeaderNextUp": "इसके बाद",
"HeaderLiveTV": "लाइव टीवी", "HeaderLiveTV": "लाइव टीवी",
@ -26,7 +26,7 @@
"AuthenticationSucceededWithUserName": "सफलता से प्रमाणीकृत", "AuthenticationSucceededWithUserName": "सफलता से प्रमाणीकृत",
"Artists": "कलाकारों", "Artists": "कलाकारों",
"Application": "एप्लिकेशन", "Application": "एप्लिकेशन",
"AppDeviceValues": "एप: {0}, मशीन: {1}", "AppDeviceValues": "एप: {0}, उपकरण: {1}",
"NotificationOptionPluginUninstalled": "प्लगइन अनइंस्टाल हो गया", "NotificationOptionPluginUninstalled": "प्लगइन अनइंस्टाल हो गया",
"NotificationOptionPluginInstalled": "प्लगइन इनस्टॉल हो गया", "NotificationOptionPluginInstalled": "प्लगइन इनस्टॉल हो गया",
"NotificationOptionPluginError": "प्लगइन फ़ैल हो गया", "NotificationOptionPluginError": "प्लगइन फ़ैल हो गया",

View File

@ -348,7 +348,7 @@ namespace Emby.Server.Implementations.Plugins
try try
{ {
var data = JsonSerializer.Serialize(manifest, _jsonOptions); var data = JsonSerializer.Serialize(manifest, _jsonOptions);
File.WriteAllText(Path.Combine(path, "meta.json"), data, Encoding.UTF8); File.WriteAllText(Path.Combine(path, "meta.json"), data);
return true; return true;
} }
#pragma warning disable CA1031 // Do not catch general exception types #pragma warning disable CA1031 // Do not catch general exception types
@ -519,7 +519,7 @@ namespace Emby.Server.Implementations.Plugins
return _plugins.Remove(plugin); return _plugins.Remove(plugin);
} }
private LocalPlugin LoadManifest(string dir) internal LocalPlugin LoadManifest(string dir)
{ {
Version? version; Version? version;
PluginManifest? manifest = null; PluginManifest? manifest = null;

View File

@ -1456,7 +1456,12 @@ namespace Emby.Server.Implementations.Session
throw new SecurityException("Unknown quick connect token"); throw new SecurityException("Unknown quick connect token");
} }
request.UserId = result.Items[0].UserId; var info = result.Items[0];
request.UserId = info.UserId;
// There's no need to keep the quick connect token in the database, as AuthenticateNewSessionInternal() issues a long lived token.
_authRepo.Delete(info);
return AuthenticateNewSessionInternal(request, false); return AuthenticateNewSessionInternal(request, false);
} }

View File

@ -0,0 +1,28 @@
using System;
namespace Jellyfin.Api.Attributes
{
/// <summary>
/// Internal produces image attribute.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class AcceptsFileAttribute : Attribute
{
private readonly string[] _contentTypes;
/// <summary>
/// Initializes a new instance of the <see cref="AcceptsFileAttribute"/> class.
/// </summary>
/// <param name="contentTypes">Content types this endpoint produces.</param>
public AcceptsFileAttribute(params string[] contentTypes)
{
_contentTypes = contentTypes;
}
/// <summary>
/// Gets the configured content types.
/// </summary>
/// <returns>the configured content types.</returns>
public string[] GetContentTypes() => _contentTypes;
}
}

View File

@ -0,0 +1,18 @@
namespace Jellyfin.Api.Attributes
{
/// <summary>
/// Produces file attribute of "image/*".
/// </summary>
public class AcceptsImageFileAttribute : AcceptsFileAttribute
{
private const string ContentType = "image/*";
/// <summary>
/// Initializes a new instance of the <see cref="AcceptsImageFileAttribute"/> class.
/// </summary>
public AcceptsImageFileAttribute()
: base(ContentType)
{
}
}
}

View File

@ -3,8 +3,10 @@ using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -88,8 +90,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? searchTerm, [FromQuery] string? searchTerm,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes,
@ -127,8 +129,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
MediaTypes = mediaTypes, MediaTypes = mediaTypes,
StartIndex = startIndex, StartIndex = startIndex,
Limit = limit, Limit = limit,
@ -287,8 +289,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? searchTerm, [FromQuery] string? searchTerm,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes,
@ -326,8 +328,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
MediaTypes = mediaTypes, MediaTypes = mediaTypes,
StartIndex = startIndex, StartIndex = startIndex,
Limit = limit, Limit = limit,

View File

@ -3,7 +3,6 @@ using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;

View File

@ -7,17 +7,11 @@ using Jellyfin.Api.Attributes;
using Jellyfin.Api.Models; using Jellyfin.Api.Models;
using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Plugins;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Plugins;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
namespace Jellyfin.Api.Controllers namespace Jellyfin.Api.Controllers
{ {

View File

@ -15,7 +15,6 @@ using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.PlaybackDtos; using Jellyfin.Api.Models.PlaybackDtos;
using Jellyfin.Api.Models.StreamingDtos; using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Dlna;

View File

@ -1,13 +1,12 @@
using System; using System;
using System.Linq; using System.Linq;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -51,7 +50,7 @@ namespace Jellyfin.Api.Controllers
public ActionResult<QueryFiltersLegacy> GetQueryFiltersLegacy( public ActionResult<QueryFiltersLegacy> GetQueryFiltersLegacy(
[FromQuery] Guid? userId, [FromQuery] Guid? userId,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes) [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes)
{ {
var user = userId.HasValue && !userId.Equals(Guid.Empty) var user = userId.HasValue && !userId.Equals(Guid.Empty)
@ -60,10 +59,10 @@ namespace Jellyfin.Api.Controllers
BaseItem? item = null; BaseItem? item = null;
if (includeItemTypes.Length != 1 if (includeItemTypes.Length != 1
|| !(string.Equals(includeItemTypes[0], nameof(BoxSet), StringComparison.OrdinalIgnoreCase) || !(includeItemTypes[0] == BaseItemKind.BoxSet
|| string.Equals(includeItemTypes[0], nameof(Playlist), StringComparison.OrdinalIgnoreCase) || includeItemTypes[0] == BaseItemKind.Playlist
|| string.Equals(includeItemTypes[0], nameof(Trailer), StringComparison.OrdinalIgnoreCase) || includeItemTypes[0] == BaseItemKind.Trailer
|| string.Equals(includeItemTypes[0], "Program", StringComparison.OrdinalIgnoreCase))) || includeItemTypes[0] == BaseItemKind.Program))
{ {
item = _libraryManager.GetParentItem(parentId, user?.Id); item = _libraryManager.GetParentItem(parentId, user?.Id);
} }
@ -72,7 +71,7 @@ namespace Jellyfin.Api.Controllers
{ {
User = user, User = user,
MediaTypes = mediaTypes, MediaTypes = mediaTypes,
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
Recursive = true, Recursive = true,
EnableTotalRecordCount = false, EnableTotalRecordCount = false,
DtoOptions = new DtoOptions DtoOptions = new DtoOptions
@ -137,7 +136,7 @@ namespace Jellyfin.Api.Controllers
public ActionResult<QueryFilters> GetQueryFilters( public ActionResult<QueryFilters> GetQueryFilters(
[FromQuery] Guid? userId, [FromQuery] Guid? userId,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery] bool? isAiring, [FromQuery] bool? isAiring,
[FromQuery] bool? isMovie, [FromQuery] bool? isMovie,
[FromQuery] bool? isSports, [FromQuery] bool? isSports,
@ -152,10 +151,10 @@ namespace Jellyfin.Api.Controllers
BaseItem? parentItem = null; BaseItem? parentItem = null;
if (includeItemTypes.Length == 1 if (includeItemTypes.Length == 1
&& (string.Equals(includeItemTypes[0], nameof(BoxSet), StringComparison.OrdinalIgnoreCase) && (includeItemTypes[0] == BaseItemKind.BoxSet
|| string.Equals(includeItemTypes[0], nameof(Playlist), StringComparison.OrdinalIgnoreCase) || includeItemTypes[0] == BaseItemKind.Playlist
|| string.Equals(includeItemTypes[0], nameof(Trailer), StringComparison.OrdinalIgnoreCase) || includeItemTypes[0] == BaseItemKind.Trailer
|| string.Equals(includeItemTypes[0], "Program", StringComparison.OrdinalIgnoreCase))) || includeItemTypes[0] == BaseItemKind.Program))
{ {
parentItem = null; parentItem = null;
} }
@ -167,7 +166,7 @@ namespace Jellyfin.Api.Controllers
var filters = new QueryFilters(); var filters = new QueryFilters();
var genreQuery = new InternalItemsQuery(user) var genreQuery = new InternalItemsQuery(user)
{ {
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
DtoOptions = new DtoOptions DtoOptions = new DtoOptions
{ {
Fields = Array.Empty<ItemFields>(), Fields = Array.Empty<ItemFields>(),
@ -192,10 +191,10 @@ namespace Jellyfin.Api.Controllers
} }
if (includeItemTypes.Length == 1 if (includeItemTypes.Length == 1
&& (string.Equals(includeItemTypes[0], nameof(MusicAlbum), StringComparison.OrdinalIgnoreCase) && (includeItemTypes[0] == BaseItemKind.MusicAlbum
|| string.Equals(includeItemTypes[0], nameof(MusicVideo), StringComparison.OrdinalIgnoreCase) || includeItemTypes[0] == BaseItemKind.MusicVideo
|| string.Equals(includeItemTypes[0], nameof(MusicArtist), StringComparison.OrdinalIgnoreCase) || includeItemTypes[0] == BaseItemKind.MusicArtist
|| string.Equals(includeItemTypes[0], nameof(Audio), StringComparison.OrdinalIgnoreCase))) || includeItemTypes[0] == BaseItemKind.Audio))
{ {
filters.Genres = _libraryManager.GetMusicGenres(genreQuery).Items.Select(i => new NameGuidPair filters.Genres = _libraryManager.GetMusicGenres(genreQuery).Items.Select(i => new NameGuidPair
{ {

View File

@ -6,6 +6,7 @@ using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -74,8 +75,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? searchTerm, [FromQuery] string? searchTerm,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
@ -96,8 +97,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
StartIndex = startIndex, StartIndex = startIndex,
Limit = limit, Limit = limit,
IsFavorite = isFavorite, IsFavorite = isFavorite,

View File

@ -2,13 +2,11 @@ using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Attributes; using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;

View File

@ -87,6 +87,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="NoContentResult"/>.</returns> /// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpPost("Users/{userId}/Images/{imageType}")] [HttpPost("Users/{userId}/Images/{imageType}")]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[AcceptsImageFile]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")]
@ -133,6 +134,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="NoContentResult"/>.</returns> /// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpPost("Users/{userId}/Images/{imageType}/{index}")] [HttpPost("Users/{userId}/Images/{imageType}/{index}")]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[AcceptsImageFile]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")]
@ -312,6 +314,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if item not found.</returns> /// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if item not found.</returns>
[HttpPost("Items/{itemId}/Images/{imageType}")] [HttpPost("Items/{itemId}/Images/{imageType}")]
[Authorize(Policy = Policies.RequiresElevation)] [Authorize(Policy = Policies.RequiresElevation)]
[AcceptsImageFile]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")]
@ -346,6 +349,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if item not found.</returns> /// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if item not found.</returns>
[HttpPost("Items/{itemId}/Images/{imageType}/{imageIndex}")] [HttpPost("Items/{itemId}/Images/{imageType}/{imageIndex}")]
[Authorize(Policy = Policies.RequiresElevation)] [Authorize(Policy = Policies.RequiresElevation)]
[AcceptsImageFile]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")]

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;

View File

@ -2,8 +2,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.IO; using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;

View File

@ -1,6 +1,5 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq; using System.Linq;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
@ -178,8 +177,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes,
@ -233,8 +232,8 @@ namespace Jellyfin.Api.Controllers
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
if (includeItemTypes.Length == 1 if (includeItemTypes.Length == 1
&& (includeItemTypes[0].Equals("Playlist", StringComparison.OrdinalIgnoreCase) && (includeItemTypes[0] == BaseItemKind.Playlist
|| includeItemTypes[0].Equals("BoxSet", StringComparison.OrdinalIgnoreCase))) || includeItemTypes[0] == BaseItemKind.BoxSet))
{ {
parentId = null; parentId = null;
} }
@ -251,7 +250,7 @@ namespace Jellyfin.Api.Controllers
&& string.Equals(hasCollectionType.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) && string.Equals(hasCollectionType.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
{ {
recursive = true; recursive = true;
includeItemTypes = new[] { "Playlist" }; includeItemTypes = new[] { BaseItemKind.Playlist };
} }
var enabledChannels = user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels); var enabledChannels = user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels);
@ -286,8 +285,8 @@ namespace Jellyfin.Api.Controllers
{ {
IsPlayed = isPlayed, IsPlayed = isPlayed,
MediaTypes = mediaTypes, MediaTypes = mediaTypes,
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
Recursive = recursive ?? false, Recursive = recursive ?? false,
OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder), OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder),
IsFavorite = isFavorite, IsFavorite = isFavorite,
@ -611,8 +610,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes,
@ -773,8 +772,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool enableTotalRecordCount = true,
[FromQuery] bool? enableImages = true) [FromQuery] bool? enableImages = true)
{ {
@ -810,8 +809,8 @@ namespace Jellyfin.Api.Controllers
CollapseBoxSetItems = false, CollapseBoxSetItems = false,
EnableTotalRecordCount = enableTotalRecordCount, EnableTotalRecordCount = enableTotalRecordCount,
AncestorIds = ancestorIds, AncestorIds = ancestorIds,
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
SearchTerm = searchTerm SearchTerm = searchTerm
}); });

View File

@ -11,7 +11,6 @@ using System.Threading.Tasks;
using Jellyfin.Api.Attributes; using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.LibraryDtos; using Jellyfin.Api.Models.LibraryDtos;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;

View File

@ -6,6 +6,7 @@ using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
@ -74,8 +75,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? searchTerm, [FromQuery] string? searchTerm,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
@ -96,8 +97,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
StartIndex = startIndex, StartIndex = startIndex,
Limit = limit, Limit = limit,
IsFavorite = isFavorite, IsFavorite = isFavorite,

View File

@ -4,7 +4,6 @@ using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using MediaBrowser.Common.Json;
using MediaBrowser.Common.Updates; using MediaBrowser.Common.Updates;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Updates; using MediaBrowser.Model.Updates;

View File

@ -3,7 +3,6 @@ using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;

View File

@ -6,7 +6,6 @@ using System.Threading.Tasks;
using Jellyfin.Api.Attributes; using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.PlaylistDtos; using Jellyfin.Api.Models.PlaylistDtos;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;

View File

@ -1,10 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Mime;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Attributes; using Jellyfin.Api.Attributes;
@ -300,9 +298,7 @@ namespace Jellyfin.Api.Controllers
} }
var imagePath = Path.Combine(plugin.Path, plugin.Manifest.ImagePath ?? string.Empty); var imagePath = Path.Combine(plugin.Path, plugin.Manifest.ImagePath ?? string.Empty);
if (((ServerConfiguration)_config.CommonConfiguration).DisablePluginImages if (plugin.Manifest.ImagePath == null || !System.IO.File.Exists(imagePath))
|| plugin.Manifest.ImagePath == null
|| !System.IO.File.Exists(imagePath))
{ {
return NotFound(); return NotFound();
} }

View File

@ -6,6 +6,7 @@ using System.Linq;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
@ -83,8 +84,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] Guid? userId, [FromQuery] Guid? userId,
[FromQuery, Required] string searchTerm, [FromQuery, Required] string searchTerm,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery] bool? isMovie, [FromQuery] bool? isMovie,
@ -109,8 +110,8 @@ namespace Jellyfin.Api.Controllers
IncludeStudios = includeStudios, IncludeStudios = includeStudios,
StartIndex = startIndex, StartIndex = startIndex,
UserId = userId ?? Guid.Empty, UserId = userId ?? Guid.Empty,
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
MediaTypes = mediaTypes, MediaTypes = mediaTypes,
ParentId = parentId, ParentId = parentId,

View File

@ -5,6 +5,7 @@ using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -73,8 +74,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? searchTerm, [FromQuery] string? searchTerm,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
@ -96,8 +97,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
StartIndex = startIndex, StartIndex = startIndex,
Limit = limit, Limit = limit,
IsFavorite = isFavorite, IsFavorite = isFavorite,

View File

@ -3,7 +3,6 @@ using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Threading; using System.Threading;

View File

@ -5,7 +5,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Mime; using System.Net.Mime;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Attributes; using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Globalization;
using MediaBrowser.Model.SyncPlay; using MediaBrowser.Model.SyncPlay;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View File

@ -148,7 +148,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes,
@ -194,7 +194,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool enableTotalRecordCount = true,
[FromQuery] bool? enableImages = true) [FromQuery] bool? enableImages = true)
{ {
var includeItemTypes = new[] { "Trailer" }; var includeItemTypes = new[] { BaseItemKind.Trailer };
return _itemsController return _itemsController
.GetItems( .GetItems(

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq; using System.Linq;
using Jellyfin.Api.Constants; using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;

View File

@ -8,6 +8,7 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
@ -269,7 +270,7 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] Guid userId, [FromRoute, Required] Guid userId,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery] bool? isPlayed, [FromQuery] bool? isPlayed,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
@ -296,7 +297,7 @@ namespace Jellyfin.Api.Controllers
new LatestItemsQuery new LatestItemsQuery
{ {
GroupItems = groupItems, GroupItems = groupItems,
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
IsPlayed = isPlayed, IsPlayed = isPlayed,
Limit = limit, Limit = limit,
ParentId = parentId ?? Guid.Empty, ParentId = parentId ?? Guid.Empty,

View File

@ -4,7 +4,6 @@ using System.ComponentModel.DataAnnotations;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.UserViewDtos; using Jellyfin.Api.Models.UserViewDtos;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;

View File

@ -12,7 +12,6 @@ using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.PlaybackDtos; using Jellyfin.Api.Models.PlaybackDtos;
using Jellyfin.Api.Models.StreamingDtos; using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Dlna;

View File

@ -74,8 +74,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
[FromQuery] Guid? parentId, [FromQuery] Guid? parentId,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
@ -101,8 +101,8 @@ namespace Jellyfin.Api.Controllers
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes),
IncludeItemTypes = includeItemTypes, IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes),
MediaTypes = mediaTypes, MediaTypes = mediaTypes,
DtoOptions = dtoOptions DtoOptions = dtoOptions
}; };
@ -193,16 +193,17 @@ namespace Jellyfin.Api.Controllers
return _dtoService.GetBaseItemDto(item, dtoOptions); return _dtoService.GetBaseItemDto(item, dtoOptions);
} }
private bool FilterItem(BaseItem f, IReadOnlyCollection<string> excludeItemTypes, IReadOnlyCollection<string> includeItemTypes, IReadOnlyCollection<string> mediaTypes) private bool FilterItem(BaseItem f, IReadOnlyCollection<BaseItemKind> excludeItemTypes, IReadOnlyCollection<BaseItemKind> includeItemTypes, IReadOnlyCollection<string> mediaTypes)
{ {
var baseItemKind = f.GetBaseItemKind();
// Exclude item types // Exclude item types
if (excludeItemTypes.Count > 0 && excludeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)) if (excludeItemTypes.Count > 0 && excludeItemTypes.Contains(baseItemKind))
{ {
return false; return false;
} }
// Include item types // Include item types
if (includeItemTypes.Count > 0 && !includeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)) if (includeItemTypes.Count > 0 && !includeItemTypes.Contains(baseItemKind))
{ {
return false; return false;
} }

View File

@ -129,5 +129,21 @@ namespace Jellyfin.Api.Helpers
TotalRecordCount = result.TotalRecordCount TotalRecordCount = result.TotalRecordCount
}; };
} }
internal static string[] GetItemTypeStrings(IReadOnlyList<BaseItemKind> itemKinds)
{
if (itemKinds.Count == 0)
{
return Array.Empty<string>();
}
var itemTypes = new string[itemKinds.Count];
for (var i = 0; i < itemKinds.Count; i++)
{
itemTypes[i] = itemKinds[i].ToString();
}
return itemTypes;
}
} }
} }

View File

@ -15,10 +15,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.2" /> <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.6.3" /> <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -38,4 +38,10 @@
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Jellyfin.Api.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,190 @@
namespace Jellyfin.Data.Enums
{
/// <summary>
/// The base item kind.
/// </summary>
/// <remarks>
/// This enum is generated from all classes that inherit from <c>BaseItem</c>.
/// </remarks>
public enum BaseItemKind
{
/// <summary>
/// Item is aggregate folder.
/// </summary>
AggregateFolder,
/// <summary>
/// Item is audio.
/// </summary>
Audio,
/// <summary>
/// Item is audio book.
/// </summary>
AudioBook,
/// <summary>
/// Item is base plugin folder.
/// </summary>
BasePluginFolder,
/// <summary>
/// Item is book.
/// </summary>
Book,
/// <summary>
/// Item is box set.
/// </summary>
BoxSet,
/// <summary>
/// Item is channel.
/// </summary>
Channel,
/// <summary>
/// Item is channel folder item.
/// </summary>
ChannelFolderItem,
/// <summary>
/// Item is collection folder.
/// </summary>
CollectionFolder,
/// <summary>
/// Item is episode.
/// </summary>
Episode,
/// <summary>
/// Item is folder.
/// </summary>
Folder,
/// <summary>
/// Item is genre.
/// </summary>
Genre,
/// <summary>
/// Item is manual playlists folder.
/// </summary>
ManualPlaylistsFolder,
/// <summary>
/// Item is movie.
/// </summary>
Movie,
/// <summary>
/// Item is music album.
/// </summary>
MusicAlbum,
/// <summary>
/// Item is music artist.
/// </summary>
MusicArtist,
/// <summary>
/// Item is music genre.
/// </summary>
MusicGenre,
/// <summary>
/// Item is music video.
/// </summary>
MusicVideo,
/// <summary>
/// Item is person.
/// </summary>
Person,
/// <summary>
/// Item is photo.
/// </summary>
Photo,
/// <summary>
/// Item is photo album.
/// </summary>
PhotoAlbum,
/// <summary>
/// Item is playlist.
/// </summary>
Playlist,
/// <summary>
/// Item is program
/// </summary>
Program,
/// <summary>
/// Item is recording.
/// </summary>
/// <remarks>
/// Manually added.
/// </remarks>
Recording,
/// <summary>
/// Item is season.
/// </summary>
Season,
/// <summary>
/// Item is series.
/// </summary>
Series,
/// <summary>
/// Item is studio.
/// </summary>
Studio,
/// <summary>
/// Item is trailer.
/// </summary>
Trailer,
/// <summary>
/// Item is live tv channel.
/// </summary>
/// <remarks>
/// Type is overridden.
/// </remarks>
TvChannel,
/// <summary>
/// Item is live tv program.
/// </summary>
/// <remarks>
/// Type is overridden.
/// </remarks>
TvProgram,
/// <summary>
/// Item is user root folder.
/// </summary>
UserRootFolder,
/// <summary>
/// Item is user view.
/// </summary>
UserView,
/// <summary>
/// Item is video.
/// </summary>
Video,
/// <summary>
/// Item is year.
/// </summary>
Year
}
}

View File

@ -19,7 +19,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Data</PackageId> <PackageId>Jellyfin.Data</PackageId>
<VersionPrefix>10.7.0</VersionPrefix> <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>
@ -41,8 +41,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -26,11 +26,11 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Linq.Async" Version="5.0.0" /> <PackageReference Include="System.Linq.Async" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.2"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.2"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -316,6 +316,7 @@ namespace Jellyfin.Server.Extensions
c.OperationFilter<SecurityRequirementsOperationFilter>(); c.OperationFilter<SecurityRequirementsOperationFilter>();
c.OperationFilter<FileResponseFilter>(); c.OperationFilter<FileResponseFilter>();
c.OperationFilter<FileRequestFilter>();
c.OperationFilter<ParameterObsoleteFilter>(); c.OperationFilter<ParameterObsoleteFilter>();
c.DocumentFilter<WebsocketModelFilter>(); c.DocumentFilter<WebsocketModelFilter>();
}); });

View File

@ -0,0 +1,43 @@
using System.Collections.Generic;
using Jellyfin.Api.Attributes;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Jellyfin.Server.Filters
{
/// <inheritdoc />
public class FileRequestFilter : IOperationFilter
{
/// <inheritdoc />
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
foreach (var attribute in context.ApiDescription.ActionDescriptor.EndpointMetadata)
{
if (attribute is AcceptsFileAttribute acceptsFileAttribute)
{
operation.RequestBody = GetRequestBody(acceptsFileAttribute.GetContentTypes());
break;
}
}
}
private static OpenApiRequestBody GetRequestBody(IEnumerable<string> contentTypes)
{
var body = new OpenApiRequestBody();
var mediaType = new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Type = "string",
Format = "binary"
}
};
foreach (var contentType in contentTypes)
{
body.Content.Add(contentType, mediaType);
}
return body;
}
}
}

View File

@ -40,8 +40,8 @@
<PackageReference Include="CommandLineParser" Version="2.8.0" /> <PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.2" /> <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="5.0.2" /> <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="5.0.3" />
<PackageReference Include="prometheus-net" Version="4.1.1" /> <PackageReference Include="prometheus-net" Version="4.1.1" />
<PackageReference Include="prometheus-net.AspNetCore" Version="4.1.1" /> <PackageReference Include="prometheus-net.AspNetCore" Version="4.1.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />

View File

@ -8,7 +8,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Common</PackageId> <PackageId>Jellyfin.Common</PackageId>
<VersionPrefix>10.7.0</VersionPrefix> <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>

View File

@ -1998,6 +1998,11 @@ namespace MediaBrowser.Controller.Entities
return GetType().Name; return GetType().Name;
} }
public BaseItemKind GetBaseItemKind()
{
return Enum.Parse<BaseItemKind>(GetClientTypeName());
}
/// <summary> /// <summary>
/// Gets the linked child. /// Gets the linked child.
/// </summary> /// </summary>

View File

@ -8,7 +8,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Controller</PackageId> <PackageId>Jellyfin.Controller</PackageId>
<VersionPrefix>10.7.0</VersionPrefix> <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,14 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
bool SupportsHwaccel(string hwaccel); bool SupportsHwaccel(string hwaccel);
/// <summary>
/// Whether given filter is supported.
/// </summary>
/// <param name="filter">The filter.</param>
/// <param name="option">The option.</param>
/// <returns><c>true</c> if the filter is supported, <c>false</c> otherwise.</returns>
bool SupportsFilter(string filter, string option);
/// <summary> /// <summary>
/// Extracts the audio image. /// Extracts the audio image.
/// </summary> /// </summary>

View File

@ -296,6 +296,38 @@ namespace MediaBrowser.MediaEncoding.Encoder
return found; return found;
} }
public bool CheckFilter(string filter, string option)
{
if (string.IsNullOrEmpty(filter))
{
return false;
}
string output = null;
try
{
output = GetProcessOutput(_encoderPath, "-h filter=" + filter);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error detecting the given filter");
}
if (output.Contains("Filter " + filter, StringComparison.Ordinal))
{
if (string.IsNullOrEmpty(option))
{
return true;
}
return output.Contains(option, StringComparison.Ordinal);
}
_logger.LogWarning("Filter: {Name} with option {Option} is not available", filter, option);
return false;
}
private IEnumerable<string> GetCodecs(Codec codec) private IEnumerable<string> GetCodecs(Codec codec)
{ {
string codecstr = codec == Codec.Encoder ? "encoders" : "decoders"; string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";

View File

@ -295,6 +295,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
return _hwaccels.Contains(hwaccel, StringComparer.OrdinalIgnoreCase); return _hwaccels.Contains(hwaccel, StringComparer.OrdinalIgnoreCase);
} }
public bool SupportsFilter(string filter, string option)
{
if (_ffmpegPath != null)
{
var validator = new EncoderValidator(_logger, _ffmpegPath);
return validator.CheckFilter(filter, option);
}
return false;
}
public bool CanEncodeToAudioCodec(string codec) public bool CanEncodeToAudioCodec(string codec)
{ {
if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase)) if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase))

View File

@ -57,7 +57,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
subEvent.Text = subEvent.Text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase); subEvent.Text = subEvent.Text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w0-9]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
trackEvents.Add(subEvent); trackEvents.Add(subEvent);
} }

View File

@ -79,7 +79,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
subEvent.Text = string.Join(ParserValues.NewLine, multiline); subEvent.Text = string.Join(ParserValues.NewLine, multiline);
subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase); subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\\d?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\[0-9]?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, "<", "&lt;", RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, "<", "&lt;", RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, ">", "&gt;", RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, ">", "&gt;", RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, "&lt;(\\/?(font|b|u|i|s))((\\s+(\\w|\\w[\\w\\-]*\\w)(\\s*=\\s*(?:\\\".*?\\\"|'.*?'|[^'\\\">\\s]+))?)+\\s*|\\s*)(\\/?)&gt;", "<$1$3$7>", RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, "&lt;(\\/?(font|b|u|i|s))((\\s+(\\w|\\w[\\w\\-]*\\w)(\\s*=\\s*(?:\\\".*?\\\"|'.*?'|[^'\\\">\\s]+))?)+\\s*|\\s*)(\\/?)&gt;", "<$1$3$7>", RegexOptions.IgnoreCase);

View File

@ -39,6 +39,8 @@ namespace MediaBrowser.Model.Configuration
public bool EnableTonemapping { get; set; } public bool EnableTonemapping { get; set; }
public bool EnableVppTonemapping { get; set; }
public string TonemappingAlgorithm { get; set; } public string TonemappingAlgorithm { get; set; }
public string TonemappingRange { get; set; } public string TonemappingRange { get; set; }
@ -65,6 +67,8 @@ namespace MediaBrowser.Model.Configuration
public bool EnableDecodingColorDepth10Vp9 { get; set; } public bool EnableDecodingColorDepth10Vp9 { get; set; }
public bool EnableEnhancedNvdecDecoder { get; set; }
public bool EnableHardwareEncoding { get; set; } public bool EnableHardwareEncoding { get; set; }
public bool AllowHevcEncoding { get; set; } public bool AllowHevcEncoding { get; set; }
@ -88,6 +92,7 @@ namespace MediaBrowser.Model.Configuration
// The left side of the dot is the platform number, and the right side is the device number on the platform. // The left side of the dot is the platform number, and the right side is the device number on the platform.
OpenclDevice = "0.0"; OpenclDevice = "0.0";
EnableTonemapping = false; EnableTonemapping = false;
EnableVppTonemapping = false;
TonemappingAlgorithm = "hable"; TonemappingAlgorithm = "hable";
TonemappingRange = "auto"; TonemappingRange = "auto";
TonemappingDesat = 0; TonemappingDesat = 0;
@ -100,6 +105,7 @@ namespace MediaBrowser.Model.Configuration
DeinterlaceMethod = "yadif"; DeinterlaceMethod = "yadif";
EnableDecodingColorDepth10Hevc = true; EnableDecodingColorDepth10Hevc = true;
EnableDecodingColorDepth10Vp9 = true; EnableDecodingColorDepth10Vp9 = true;
EnableEnhancedNvdecDecoder = true;
EnableHardwareEncoding = true; EnableHardwareEncoding = true;
AllowHevcEncoding = true; AllowHevcEncoding = true;
EnableSubtitleExtraction = true; EnableSubtitleExtraction = true;

View File

@ -418,8 +418,6 @@ namespace MediaBrowser.Model.Configuration
public PathSubstitution[] PathSubstitutions { get; set; } = Array.Empty<PathSubstitution>(); public PathSubstitution[] PathSubstitutions { get; set; } = Array.Empty<PathSubstitution>();
public bool EnableSimpleArtistDetection { get; set; } = false;
public string[] UninstalledPlugins { get; set; } = Array.Empty<string>(); public string[] UninstalledPlugins { get; set; } = Array.Empty<string>();
/// <summary> /// <summary>
@ -461,10 +459,5 @@ namespace MediaBrowser.Model.Configuration
/// Gets or sets a value indicating whether older plugins should automatically be deleted from the plugin folder. /// Gets or sets a value indicating whether older plugins should automatically be deleted from the plugin folder.
/// </summary> /// </summary>
public bool RemoveOldPlugins { get; set; } public bool RemoveOldPlugins { get; set; }
/// <summary>
/// Gets or sets a value indicating whether plugin image should be disabled.
/// </summary>
public bool DisablePluginImages { get; set; }
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Jellyfin.Data.Enums;
using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Library; using MediaBrowser.Model.Library;
@ -276,7 +277,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the type. /// Gets or sets the type.
/// </summary> /// </summary>
/// <value>The type.</value> /// <value>The type.</value>
public string Type { get; set; } public BaseItemKind Type { get; set; }
/// <summary> /// <summary>
/// Gets or sets the people. /// Gets or sets the people.

View File

@ -8,7 +8,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Model</PackageId> <PackageId>Jellyfin.Model</PackageId>
<VersionPrefix>10.7.0</VersionPrefix> <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>

View File

@ -721,20 +721,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break; break;
} }
case "musicBrainzArtistID":
{
if (reader.IsEmptyElement)
{
reader.Read();
break;
}
var id = reader.ReadElementContentAsString();
item.SetProviderId(MetadataProvider.MusicBrainzArtist.ToString(), id);
break;
}
default: default:
string readerName = reader.Name; string readerName = reader.Name;
if (_validProviderIds.TryGetValue(readerName, out string? providerIdValue)) if (_validProviderIds.TryGetValue(readerName, out string? providerIdValue))

View File

@ -1,4 +1,4 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("10.7.0")] [assembly: AssemblyVersion("10.8.0")]
[assembly: AssemblyFileVersion("10.7.0")] [assembly: AssemblyFileVersion("10.8.0")]

View File

@ -1,7 +1,7 @@
--- ---
# We just wrap `build` so this is really it # We just wrap `build` so this is really it
name: "jellyfin" name: "jellyfin"
version: "10.7.0" version: "10.8.0"
packages: packages:
- debian.amd64 - debian.amd64
- debian.arm64 - debian.arm64

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
jellyfin-server (10.8.0-1) unstable; urgency=medium
* Forthcoming stable release
-- Jellyfin Packaging Team <packaging@jellyfin.org> Fri, 04 Dec 2020 21:55:12 -0500
jellyfin-server (10.7.0-1) unstable; urgency=medium jellyfin-server (10.7.0-1) unstable; urgency=medium
* Forthcoming stable release * Forthcoming stable release

View File

@ -5,7 +5,7 @@ Homepage: https://jellyfin.org
Standards-Version: 3.9.2 Standards-Version: 3.9.2
Package: jellyfin Package: jellyfin
Version: 10.7.0 Version: 10.8.0
Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org> Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org>
Depends: jellyfin-server, jellyfin-web Depends: jellyfin-server, jellyfin-web
Description: Provides the Jellyfin Free Software Media System Description: Provides the Jellyfin Free Software Media System

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -15,7 +15,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -16,7 +16,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -15,7 +15,7 @@ RUN apt-get update \
# Install dotnet repository # Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/7f736160-9f34-4595-8d72-13630c437aef/b9c4513afb0f8872eb95793c70ac52f6/dotnet-sdk-5.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ RUN wget https://download.visualstudio.microsoft.com/download/pr/a2052604-de46-4cd4-8256-9bc222537d32/a798771950904eaf91c0c37c58f516e1/dotnet-sdk-5.0.103-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \ && mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@ -7,7 +7,7 @@
%endif %endif
Name: jellyfin Name: jellyfin
Version: 10.7.0 Version: 10.8.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: The Free Software Media System Summary: The Free Software Media System
License: GPLv3 License: GPLv3
@ -137,6 +137,8 @@ fi
%systemd_postun_with_restart jellyfin.service %systemd_postun_with_restart jellyfin.service
%changelog %changelog
* Fri Dec 04 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org> * Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release - Forthcoming stable release
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org> * Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>

View File

@ -6,11 +6,11 @@ using Xunit;
namespace Jellyfin.Api.Tests.Helpers namespace Jellyfin.Api.Tests.Helpers
{ {
public class RequestHelpersTests public static class RequestHelpersTests
{ {
[Theory] [Theory]
[MemberData(nameof(GetOrderBy_Success_TestData))] [MemberData(nameof(GetOrderBy_Success_TestData))]
public void GetOrderBy_Success(IReadOnlyList<string> sortBy, IReadOnlyList<SortOrder> requestedSortOrder, (string, SortOrder)[] expected) public static void GetOrderBy_Success(IReadOnlyList<string> sortBy, IReadOnlyList<SortOrder> requestedSortOrder, (string, SortOrder)[] expected)
{ {
Assert.Equal(expected, RequestHelpers.GetOrderBy(sortBy, requestedSortOrder)); Assert.Equal(expected, RequestHelpers.GetOrderBy(sortBy, requestedSortOrder));
} }
@ -55,5 +55,35 @@ namespace Jellyfin.Api.Tests.Helpers
} }
}; };
} }
[Fact]
public static void GetItemTypeStrings_Empty_Empty()
{
Assert.Empty(RequestHelpers.GetItemTypeStrings(Array.Empty<BaseItemKind>()));
}
[Fact]
public static void GetItemTypeStrings_Valid_Success()
{
BaseItemKind[] input =
{
BaseItemKind.AggregateFolder,
BaseItemKind.Audio,
BaseItemKind.BasePluginFolder,
BaseItemKind.CollectionFolder
};
string[] expected =
{
"AggregateFolder",
"Audio",
"BasePluginFolder",
"CollectionFolder"
};
var res = RequestHelpers.GetItemTypeStrings(input);
Assert.Equal(expected, res);
}
} }
} }

View File

@ -16,7 +16,7 @@
<PackageReference Include="AutoFixture" Version="4.15.0" /> <PackageReference Include="AutoFixture" Version="4.15.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.15.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.15.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.15.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.15.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.2" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />

Some files were not shown because too many files have changed in this diff Show More