Merge branch 'master' into providermanager-cleanup

pull/7039/head
Claus Vium 2 years ago committed by GitHub
commit 81b04ddbb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -26,6 +26,8 @@ jobs:
BuildConfiguration: linux.amd64-musl
Linux.arm64:
BuildConfiguration: linux.arm64
Linux.musl-linux-arm64:
BuildConfiguration: linux.musl-linux-arm64
Linux.armhf:
BuildConfiguration: linux.armhf
Windows.amd64:

@ -22,16 +22,16 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup .NET Core
uses: actions/setup-dotnet@v2
uses: actions/setup-dotnet@v3
with:
dotnet-version: '6.0.x'
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-extended
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

@ -29,7 +29,7 @@ jobs:
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.5
uses: cirrus-actions/rebase@1.7
env:
GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }}

@ -17,13 +17,13 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Setup .NET Core
uses: actions/setup-dotnet@v2
uses: actions/setup-dotnet@v3
with:
dotnet-version: '6.0.x'
- name: Generate openapi.json
run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
- name: Upload openapi.json
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: openapi-head
retention-days: 14
@ -41,13 +41,13 @@ jobs:
with:
ref: ${{ github.base_ref }}
- name: Setup .NET Core
uses: actions/setup-dotnet@v2
uses: actions/setup-dotnet@v3
with:
dotnet-version: '6.0.x'
- name: Generate openapi.json
run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
- name: Upload openapi.json
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: openapi-base
retention-days: 14
@ -63,12 +63,12 @@ jobs:
- openapi-base
steps:
- name: Download openapi-head
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: openapi-head
path: openapi-head
- name: Download openapi-base
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: openapi-base
path: openapi-base

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ contains(github.repository, 'jellyfin/') }}
steps:
- uses: actions/stale@v5
- uses: actions/stale@v6
with:
repo-token: ${{ secrets.JF_BOT_TOKEN }}
days-before-stale: 120

@ -36,6 +36,7 @@
- [dmitrylyzo](https://github.com/dmitrylyzo)
- [DMouse10462](https://github.com/DMouse10462)
- [DrPandemic](https://github.com/DrPandemic)
- [eglia](https://github.com/eglia)
- [EraYaN](https://github.com/EraYaN)
- [escabe](https://github.com/escabe)
- [excelite](https://github.com/excelite)
@ -147,6 +148,7 @@
- [xosdy](https://github.com/xosdy)
- [XVicarious](https://github.com/XVicarious)
- [YouKnowBlom](https://github.com/YouKnowBlom)
- [ZachPhelan](https://github.com/ZachPhelan)
- [KristupasSavickas](https://github.com/KristupasSavickas)
- [Pusta](https://github.com/pusta)
- [nielsvanvelzen](https://github.com/nielsvanvelzen)
@ -157,6 +159,7 @@
- [jonas-resch](https://github.com/jonas-resch)
- [vgambier](https://github.com/vgambier)
- [MinecraftPlaye](https://github.com/MinecraftPlaye)
- [RealGreenDragon](https://github.com/RealGreenDragon)
# Emby Contributors
@ -225,3 +228,4 @@
- [gnuyent](https://github.com/gnuyent)
- [Matthew Jones](https://github.com/matthew-jones-uk)
- [Jakob Kukla](https://github.com/jakobkukla)
- [Utku Özdemir](https://github.com/utkuozdemir)

@ -31,7 +31,7 @@ ARG LEVEL_ZERO_VERSION=1.3.22549
# mesa-va-drivers: needed for AMD VAAPI. Mesa >= 20.1 is required for HEVC transcoding.
# curl: healthcheck
RUN apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gnupg wget apt-transport-https curl \
&& apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gnupg wget curl \
&& wget -O - https://repo.jellyfin.org/jellyfin_team.gpg.key | apt-key add - \
&& echo "deb [arch=$( dpkg --print-architecture )] https://repo.jellyfin.org/$( awk -F'=' '/^ID=/{ print $NF }' /etc/os-release ) $( awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release ) main" | tee /etc/apt/sources.list.d/jellyfin.list \
&& apt-get update \
@ -53,7 +53,7 @@ RUN apt-get update \
&& dpkg -i *.deb \
&& cd .. \
&& rm -rf intel-compute-runtime \
&& apt-get remove gnupg wget apt-transport-https -y \
&& apt-get remove gnupg wget -y \
&& apt-get clean autoclean -y \
&& apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/* \
@ -72,7 +72,7 @@ COPY . .
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:DebugSymbols=false;DebugType=none"
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 -p:DebugSymbols=false -p:DebugType=none
FROM app

@ -38,9 +38,6 @@ RUN apt-get update \
libssl-dev \
libfontconfig1 \
libfreetype6 \
libomxil-bellagio0 \
libomxil-bellagio-bin \
libraspberrypi0 \
vainfo \
libva2 \
locales \
@ -64,7 +61,7 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r
# Build
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:DebugSymbols=false;DebugType=none"
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm -p:DebugSymbols=false -p:DebugType=none
FROM app

@ -55,7 +55,7 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r
# Build
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:DebugSymbols=false;DebugType=none"
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 -p:DebugSymbols=false -p:DebugType=none
FROM app

@ -13,7 +13,7 @@ namespace Emby.Dlna.Configuration
public DlnaOptions()
{
EnablePlayTo = true;
EnableServer = true;
EnableServer = false;
BlastAliveMessages = true;
SendOnlyMatchedHost = true;
ClientDiscoveryIntervalSeconds = 60;

@ -103,10 +103,7 @@ namespace Emby.Dlna.ContentDirectory
/// <inheritdoc />
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
ArgumentNullException.ThrowIfNull(request);
var profile = _dlna.GetProfile(request.Headers) ?? _dlna.GetDefaultProfile();

@ -114,15 +114,9 @@ namespace Emby.Dlna.ContentDirectory
/// <inheritdoc />
protected override void WriteResult(string methodName, IReadOnlyDictionary<string, string> methodParams, XmlWriter xmlWriter)
{
if (xmlWriter == null)
{
throw new ArgumentNullException(nameof(xmlWriter));
}
ArgumentNullException.ThrowIfNull(xmlWriter);
if (methodParams == null)
{
throw new ArgumentNullException(nameof(methodParams));
}
ArgumentNullException.ThrowIfNull(methodParams);
const string DeviceId = "test";

@ -221,6 +221,7 @@ namespace Emby.Dlna.Didl
streamInfo.IsDirectStream,
streamInfo.RunTimeTicks ?? 0,
streamInfo.TargetVideoProfile,
streamInfo.TargetVideoRangeType,
streamInfo.TargetVideoLevel,
streamInfo.TargetFramerate ?? 0,
streamInfo.TargetPacketLength,
@ -376,6 +377,7 @@ namespace Emby.Dlna.Didl
targetHeight,
streamInfo.TargetVideoBitDepth,
streamInfo.TargetVideoProfile,
streamInfo.TargetVideoRangeType,
streamInfo.TargetVideoLevel,
streamInfo.TargetFramerate ?? 0,
streamInfo.TargetPacketLength,
@ -444,7 +446,7 @@ namespace Emby.Dlna.Didl
/// </summary>
/// <remarks>
/// If context is a season, this will return a string containing just episode number and name.
/// Otherwise the result will include series nams and season number.
/// Otherwise the result will include series names and season number.
/// </remarks>
/// <param name="episode">The episode.</param>
/// <param name="context">Current context.</param>

@ -1,4 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
@ -61,6 +62,7 @@ namespace Emby.Dlna
try
{
await ExtractSystemProfilesAsync().ConfigureAwait(false);
Directory.CreateDirectory(UserProfilesPath);
LoadProfiles();
}
catch (Exception ex)
@ -100,10 +102,7 @@ namespace Emby.Dlna
/// <inheritdoc />
public DeviceProfile? GetProfile(DeviceIdentification deviceInfo)
{
if (deviceInfo == null)
{
throw new ArgumentNullException(nameof(deviceInfo));
}
ArgumentNullException.ThrowIfNull(deviceInfo);
var profile = GetProfiles()
.FirstOrDefault(i => i.Identification != null && IsMatch(deviceInfo, i.Identification));
@ -123,7 +122,7 @@ namespace Emby.Dlna
/// <summary>
/// Attempts to match a device with a profile.
/// Rules:
/// - If the profile field has no value, the field matches irregardless of its contents.
/// - If the profile field has no value, the field matches regardless of its contents.
/// - the profile field can be an exact match, or a reg exp.
/// </summary>
/// <param name="deviceInfo">The <see cref="DeviceIdentification"/> of the device.</param>
@ -170,10 +169,7 @@ namespace Emby.Dlna
/// <inheritdoc />
public DeviceProfile? GetProfile(IHeaderDictionary headers)
{
if (headers == null)
{
throw new ArgumentNullException(nameof(headers));
}
ArgumentNullException.ThrowIfNull(headers);
var profile = GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification));
if (profile == null)
@ -328,32 +324,28 @@ namespace Emby.Dlna
var path = Path.Join(
systemProfilesPath,
Path.GetFileName(name.AsSpan()).Slice(namespaceName.Length));
Path.GetFileName(name.AsSpan())[namespaceName.Length..]);
if (File.Exists(path))
{
continue;
}
// The stream should exist as we just got its name from GetManifestResourceNames
using (var stream = _assembly.GetManifestResourceStream(name)!)
{
var length = stream.Length;
var fileInfo = _fileSystem.GetFileInfo(path);
Directory.CreateDirectory(systemProfilesPath);
if (!fileInfo.Exists || fileInfo.Length != length)
var fileOptions = AsyncFile.WriteOptions;
fileOptions.Mode = FileMode.CreateNew;
fileOptions.PreallocationSize = stream.Length;
var fileStream = new FileStream(path, fileOptions);
await using (fileStream.ConfigureAwait(false))
{
Directory.CreateDirectory(systemProfilesPath);
var fileOptions = AsyncFile.WriteOptions;
fileOptions.Mode = FileMode.Create;
fileOptions.PreallocationSize = length;
var fileStream = new FileStream(path, fileOptions);
await using (fileStream.ConfigureAwait(false))
{
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
}
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
}
}
}
// Not necessary, but just to make it easy to find
Directory.CreateDirectory(UserProfilesPath);
}
/// <inheritdoc />
@ -406,14 +398,20 @@ namespace Emby.Dlna
}
var current = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, profileId, StringComparison.OrdinalIgnoreCase));
if (current.Info.Type == DeviceProfileType.System)
{
throw new ArgumentException("System profiles can't be edited");
}
var newFilename = _fileSystem.GetValidFilename(profile.Name) + ".xml";
var path = Path.Combine(UserProfilesPath, newFilename);
var path = Path.Join(UserProfilesPath, newFilename);
if (!string.Equals(path, current.Path, StringComparison.Ordinal) &&
current.Info.Type != DeviceProfileType.System)
if (!string.Equals(path, current.Path, StringComparison.Ordinal))
{
_fileSystem.DeleteFile(current.Path);
lock (_profiles)
{
_profiles.Remove(current.Path);
}
}
SaveProfile(profile, path, DeviceProfileType.User);
@ -496,72 +494,4 @@ namespace Emby.Dlna
internal string Path { get; }
}
}
/*
class DlnaProfileEntryPoint : IServerEntryPoint
{
private readonly IApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem;
private readonly IXmlSerializer _xmlSerializer;
public DlnaProfileEntryPoint(IApplicationPaths appPaths, IFileSystem fileSystem, IXmlSerializer xmlSerializer)
{
_appPaths = appPaths;
_fileSystem = fileSystem;
_xmlSerializer = xmlSerializer;
}
public void Run()
{
DumpProfiles();
}
private void DumpProfiles()
{
DeviceProfile[] list = new[]
{
new SamsungSmartTvProfile(),
new XboxOneProfile(),
new SonyPs3Profile(),
new SonyPs4Profile(),
new SonyBravia2010Profile(),
new SonyBravia2011Profile(),
new SonyBravia2012Profile(),
new SonyBravia2013Profile(),
new SonyBravia2014Profile(),
new SonyBlurayPlayer2013(),
new SonyBlurayPlayer2014(),
new SonyBlurayPlayer2015(),
new SonyBlurayPlayer2016(),
new SonyBlurayPlayerProfile(),
new PanasonicVieraProfile(),
new WdtvLiveProfile(),
new DenonAvrProfile(),
new LinksysDMA2100Profile(),
new LgTvProfile(),
new Foobar2000Profile(),
new SharpSmartTvProfile(),
new MediaMonkeyProfile(),
// new Windows81Profile(),
// new WindowsMediaCenterProfile(),
// new WindowsPhoneProfile(),
new DirectTvProfile(),
new DishHopperJoeyProfile(),
new DefaultProfile(),
new PopcornHourProfile(),
new MarantzProfile()
};
foreach (var item in list)
{
var path = Path.Combine(_appPaths.ProgramDataPath, _fileSystem.GetValidFilename(item.Name) + ".xml");
_xmlSerializer.SerializeToFile(item, path);
}
}
public void Dispose()
{
}
}*/
}

@ -33,7 +33,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

@ -16,7 +16,7 @@ namespace Emby.Dlna
/// </summary>
/// <param name="subscriptionId">The subscription identifier.</param>
/// <param name="notificationType">The notification type.</param>
/// <param name="requestedTimeoutString">The requested timeout as a sting.</param>
/// <param name="requestedTimeoutString">The requested timeout as a string.</param>
/// <param name="callbackUrl">The callback url.</param>
/// <returns>The response.</returns>
EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl);
@ -25,7 +25,7 @@ namespace Emby.Dlna
/// Creates the event subscription.
/// </summary>
/// <param name="notificationType">The notification type.</param>
/// <param name="requestedTimeoutString">The requested timeout as a sting.</param>
/// <param name="requestedTimeoutString">The requested timeout as a string.</param>
/// <param name="callbackUrl">The callback url.</param>
/// <returns>The response.</returns>
EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl);

@ -313,7 +313,7 @@ namespace Emby.Dlna.Main
_logger.LogInformation("Registering publisher for {ResourceName} on {DeviceAddress}", fullService, address);
var uri = new UriBuilder(_appHost.GetApiUrlForLocalAccess(false) + descriptorUri);
var uri = new UriBuilder(_appHost.GetApiUrlForLocalAccess(address, false) + descriptorUri);
var device = new SsdpRootDevice
{

@ -235,7 +235,7 @@ namespace Emby.Dlna.PlayTo
_logger.LogDebug("Setting mute");
var value = mute ? 1 : 0;
await new SsdpHttpClient(_httpClientFactory)
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
service,
@ -276,7 +276,7 @@ namespace Emby.Dlna.PlayTo
// Remote control will perform better
Volume = value;
await new SsdpHttpClient(_httpClientFactory)
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
service,
@ -303,7 +303,7 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException("Unable to find service");
}
await new SsdpHttpClient(_httpClientFactory)
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
service,
@ -343,7 +343,7 @@ namespace Emby.Dlna.PlayTo
}
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
await new SsdpHttpClient(_httpClientFactory)
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
service,
@ -400,7 +400,8 @@ namespace Emby.Dlna.PlayTo
}
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header, cancellationToken)
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header, cancellationToken)
.ConfigureAwait(false);
}
@ -428,7 +429,7 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException("Unable to find service");
}
return new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
return new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@ -461,7 +462,7 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
await new SsdpHttpClient(_httpClientFactory)
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
service,
@ -485,7 +486,7 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
await new SsdpHttpClient(_httpClientFactory)
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
service,
@ -618,7 +619,7 @@ namespace Emby.Dlna.PlayTo
return;
}
var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@ -668,7 +669,7 @@ namespace Emby.Dlna.PlayTo
return;
}
var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@ -701,7 +702,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@ -747,7 +748,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@ -819,7 +820,7 @@ namespace Emby.Dlna.PlayTo
return (false, null);
}
var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@ -930,10 +931,7 @@ namespace Emby.Dlna.PlayTo
private static UBaseObject CreateUBaseObject(XElement container, string trackUri)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
ArgumentNullException.ThrowIfNull(container);
var url = container.GetValue(UPnpNamespaces.Res);
@ -957,10 +955,7 @@ namespace Emby.Dlna.PlayTo
private static string[] GetProtocolInfo(XElement container)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
ArgumentNullException.ThrowIfNull(container);
var resElement = container.Element(UPnpNamespaces.Res);
@ -997,7 +992,7 @@ namespace Emby.Dlna.PlayTo
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
var httpClient = new SsdpHttpClient(_httpClientFactory);
var httpClient = new DlnaHttpClient(_logger, _httpClientFactory);
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
if (document == null)
@ -1029,7 +1024,7 @@ namespace Emby.Dlna.PlayTo
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
var httpClient = new SsdpHttpClient(_httpClientFactory);
var httpClient = new DlnaHttpClient(_logger, _httpClientFactory);
_logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
if (document == null)
@ -1064,7 +1059,7 @@ namespace Emby.Dlna.PlayTo
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken)
{
var ssdpHttpClient = new SsdpHttpClient(httpClientFactory);
var ssdpHttpClient = new DlnaHttpClient(logger, httpClientFactory);
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
if (document == null)
@ -1182,10 +1177,7 @@ namespace Emby.Dlna.PlayTo
#nullable enable
private static DeviceIcon CreateIcon(XElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
ArgumentNullException.ThrowIfNull(element);
var width = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("width"));
var height = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("height"));

@ -0,0 +1,108 @@
#pragma warning disable CS1591
using System;
using System.Globalization;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using Emby.Dlna.Common;
using MediaBrowser.Common.Net;
using Microsoft.Extensions.Logging;
namespace Emby.Dlna.PlayTo
{
public class DlnaHttpClient
{
private readonly ILogger _logger;
private readonly IHttpClientFactory _httpClientFactory;
public DlnaHttpClient(ILogger logger, IHttpClientFactory httpClientFactory)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
}
private static string NormalizeServiceUrl(string baseUrl, string serviceUrl)
{
// If it's already a complete url, don't stick anything onto the front of it
if (serviceUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
return serviceUrl;
}
if (!serviceUrl.StartsWith('/'))
{
serviceUrl = "/" + serviceUrl;
}
return baseUrl + serviceUrl;
}
private async Task<XDocument?> SendRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
using var response = await _httpClientFactory.CreateClient(NamedClient.Dlna).SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
try
{
return await XDocument.LoadAsync(
stream,
LoadOptions.None,
cancellationToken).ConfigureAwait(false);
}
catch (XmlException ex)
{
_logger.LogError(ex, "Failed to parse response");
if (_logger.IsEnabled(LogLevel.Debug))
{
_logger.LogDebug("Malformed response: {Content}\n", await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false));
}
return null;
}
}
public async Task<XDocument?> GetDataAsync(string url, CancellationToken cancellationToken)
{
using var request = new HttpRequestMessage(HttpMethod.Get, url);
// Have to await here instead of returning the Task directly, otherwise request would be disposed too soon
return await SendRequestAsync(request, cancellationToken).ConfigureAwait(false);
}
public async Task<XDocument?> SendCommandAsync(
string baseUrl,
DeviceService service,
string command,
string postData,
string? header = null,
CancellationToken cancellationToken = default)
{
using var request = new HttpRequestMessage(HttpMethod.Post, NormalizeServiceUrl(baseUrl, service.ControlUrl))
{
Content = new StringContent(postData, Encoding.UTF8, MediaTypeNames.Text.Xml)
};
request.Headers.TryAddWithoutValidation(
"SOAPACTION",
string.Format(
CultureInfo.InvariantCulture,
"\"{0}#{1}\"",
service.ServiceType,
command));
request.Headers.Pragma.ParseAdd("no-cache");
if (!string.IsNullOrEmpty(header))
{
request.Headers.TryAddWithoutValidation("contentFeatures.dlna.org", header);
}
// Have to await here instead of returning the Task directly, otherwise request would be disposed too soon
return await SendRequestAsync(request, cancellationToken).ConfigureAwait(false);
}
}
}

@ -561,6 +561,7 @@ namespace Emby.Dlna.PlayTo
streamInfo.IsDirectStream,
streamInfo.RunTimeTicks ?? 0,
streamInfo.TargetVideoProfile,
streamInfo.TargetVideoRangeType,
streamInfo.TargetVideoLevel,
streamInfo.TargetFramerate ?? 0,
streamInfo.TargetPacketLength,

@ -1,141 +0,0 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Globalization;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Emby.Dlna.Common;
using MediaBrowser.Common.Net;
namespace Emby.Dlna.PlayTo
{
public class SsdpHttpClient
{
private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50";
private const string FriendlyName = "Jellyfin";
private readonly IHttpClientFactory _httpClientFactory;
public SsdpHttpClient(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<XDocument> SendCommandAsync(
string baseUrl,
DeviceService service,
string command,
string postData,
string header = null,
CancellationToken cancellationToken = default)
{
var url = NormalizeServiceUrl(baseUrl, service.ControlUrl);
using var response = await PostSoapDataAsync(
url,
$"\"{service.ServiceType}#{command}\"",
postData,
header,
cancellationToken)
.ConfigureAwait(false);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
return await XDocument.LoadAsync(
stream,
LoadOptions.None,
cancellationToken).ConfigureAwait(false);
}
private static string NormalizeServiceUrl(string baseUrl, string serviceUrl)
{
// If it's already a complete url, don't stick anything onto the front of it
if (serviceUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
return serviceUrl;
}
if (!serviceUrl.StartsWith('/'))
{
serviceUrl = "/" + serviceUrl;
}
return baseUrl + serviceUrl;
}
public async Task SubscribeAsync(
string url,
string ip,
int port,
string localIp,
int eventport,
int timeOut = 3600)
{
using var options = new HttpRequestMessage(new HttpMethod("SUBSCRIBE"), url);
options.Headers.UserAgent.ParseAdd(USERAGENT);
options.Headers.TryAddWithoutValidation("HOST", ip + ":" + port.ToString(CultureInfo.InvariantCulture));
options.Headers.TryAddWithoutValidation("CALLBACK", "<" + localIp + ":" + eventport.ToString(CultureInfo.InvariantCulture) + ">");
options.Headers.TryAddWithoutValidation("NT", "upnp:event");
options.Headers.TryAddWithoutValidation("TIMEOUT", "Second-" + timeOut.ToString(CultureInfo.InvariantCulture));
using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
.SendAsync(options, HttpCompletionOption.ResponseHeadersRead)
.ConfigureAwait(false);
response.EnsureSuccessStatusCode();
}
public async Task<XDocument> GetDataAsync(string url, CancellationToken cancellationToken)
{
using var options = new HttpRequestMessage(HttpMethod.Get, url);
options.Headers.UserAgent.ParseAdd(USERAGENT);
options.Headers.TryAddWithoutValidation("FriendlyName.DLNA.ORG", FriendlyName);
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
try
{
return await XDocument.LoadAsync(
stream,
LoadOptions.None,
cancellationToken).ConfigureAwait(false);
}
catch
{
return null;
}
}
private async Task<HttpResponseMessage> PostSoapDataAsync(
string url,
string soapAction,
string postData,
string header,
CancellationToken cancellationToken)
{
if (soapAction[0] != '\"')
{
soapAction = $"\"{soapAction}\"";
}
using var options = new HttpRequestMessage(HttpMethod.Post, url);
options.Headers.UserAgent.ParseAdd(USERAGENT);
options.Headers.TryAddWithoutValidation("SOAPACTION", soapAction);
options.Headers.TryAddWithoutValidation("Pragma", "no-cache");
options.Headers.TryAddWithoutValidation("FriendlyName.DLNA.ORG", FriendlyName);
if (!string.IsNullOrEmpty(header))
{
options.Headers.TryAddWithoutValidation("contentFeatures.dlna.org", header);
}
options.Content = new StringContent(postData, Encoding.UTF8, MediaTypeNames.Text.Xml);
return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
}
}
}

@ -61,10 +61,7 @@ namespace Emby.Dlna.PlayTo
private static Argument ArgumentFromXml(XElement container)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
ArgumentNullException.ThrowIfNull(container);
return new Argument
{

@ -10,10 +10,7 @@ namespace Emby.Dlna.PlayTo
{
public static UBaseObject Create(XElement container)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
ArgumentNullException.ThrowIfNull(container);
return new UBaseObject
{

@ -54,10 +54,7 @@ namespace Emby.Dlna.PlayTo
public bool Equals(UBaseObject obj)
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
ArgumentNullException.ThrowIfNull(obj);
return string.Equals(Id, obj.Id, StringComparison.Ordinal);
}

@ -2,7 +2,6 @@
using System;
using System.Globalization;
using System.Linq;
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
@ -164,18 +163,5 @@ namespace Emby.Dlna.Profiles
}
};
}
public void AddXmlRootAttribute(string name, string value)
{
var list = XmlRootAttributes.ToList();
list.Add(new XmlAttribute
{
Name = name,
Value = value
});
XmlRootAttributes = list.ToArray();
}
}
}

@ -1,34 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class DenonAvrProfile : DefaultProfile
{
public DenonAvrProfile()
{
Name = "Denon AVR";
SupportedMediaTypes = "Audio";
Identification = new DeviceIdentification
{
FriendlyName = @"Denon:\[AVR:.*",
Manufacturer = "Denon"
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mp3,flac,m4a,wma",
Type = DlnaProfileType.Audio
},
};
ResponseProfiles = System.Array.Empty<ResponseProfile>();
}
}
}

@ -1,129 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class DirectTvProfile : DefaultProfile
{
public DirectTvProfile()
{
Name = "DirecTV HD-DVR";
TimelineOffsetSeconds = 10;
RequiresPlainFolders = true;
RequiresPlainVideoItems = true;
Identification = new DeviceIdentification
{
Headers = new[]
{
new HttpHeaderInfo
{
Match = HeaderMatchType.Substring,
Name = "User-Agent",
Value = "DIRECTV"
}
},
FriendlyName = "^DIRECTV.*$"
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video",
AudioCodec = "mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "jpeg,jpg",
Type = DlnaProfileType.Photo
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video",
AudioCodec = "mp2",
Type = DlnaProfileType.Video
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Codec = "mpeg2video",
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "8192000"
}
}
},
new CodecProfile
{
Codec = "mp2",
Type = CodecType.Audio,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
ResponseProfiles = System.Array.Empty<ResponseProfile>();
}
}
}

@ -1,228 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class DishHopperJoeyProfile : DefaultProfile
{
public DishHopperJoeyProfile()
{
Name = "Dish Hopper-Joey";
ProtocolInfo = "http-get:*:video/mp2t:*,http-get:*:video/mpeg:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*";
Identification = new DeviceIdentification
{
Manufacturer = "Echostar Technologies LLC",
ManufacturerUrl = "http://www.echostar.com",
Headers = new[]
{
new HttpHeaderInfo
{
Match = HeaderMatchType.Substring,
Name = "User-Agent",
Value = "Zip_"
}
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "mp4",
Type = DlnaProfileType.Video,
AudioCodec = "aac",
VideoCodec = "h264"
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mp4,mkv,mpeg,ts",
VideoCodec = "h264,mpeg2video",
AudioCodec = "mp3,ac3,aac,he-aac,pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3,alac,flac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920",
IsRequired = true
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080",
IsRequired = true
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30",
IsRequired = true
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000",
IsRequired = true
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41",
IsRequired = true
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920",
IsRequired = true
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080",
IsRequired = true
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30",
IsRequired = true
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000",
IsRequired = true
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "ac3,he-aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6",
IsRequired = true
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2",
IsRequired = true
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Conditions = new[]
{
// The device does not have any audio switching capabilities
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.IsSecondaryAudio,
Value = "false"
}
}
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "mkv,ts,mpegts",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,78 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class Foobar2000Profile : DefaultProfile
{
public Foobar2000Profile()
{
Name = "foobar2000";
SupportedMediaTypes = "Audio";
Identification = new DeviceIdentification
{
FriendlyName = @"foobar",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "foobar",
Match = HeaderMatchType.Substring
}
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp2,mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp4",
AudioCodec = "mp4",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "aac,wav",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "flac",
AudioCodec = "flac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "ogg",
AudioCodec = "vorbis",
Type = DlnaProfileType.Audio
}
};
ResponseProfiles = System.Array.Empty<ResponseProfile>();
}
}
}

@ -1,211 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class LgTvProfile : DefaultProfile
{
public LgTvProfile()
{
Name = "LG Smart TV";
TimelineOffsetSeconds = 10;
Identification = new DeviceIdentification
{
FriendlyName = @"LG.*",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "LG",
Match = HeaderMatchType.Substring
}
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
AudioCodec = "ac3,aac,mp3",
VideoCodec = "h264",
Type = DlnaProfileType.Video
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts,mpegts,avi,mkv,m2ts",
VideoCodec = "h264",
AudioCodec = "aac,ac3,eac3,mp3,dca,dts",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,m4v",
VideoCodec = "h264,mpeg4",
AudioCodec = "aac,ac3,eac3,mp3,dca,dts",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "mpeg4",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "ac3,eac3,aac,mp3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
},
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.External
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
},
new ResponseProfile
{
Container = "ts,mpegts",
Type = DlnaProfileType.Video,
MimeType = "video/mpeg"
}
};
}
}
}

@ -1,55 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class LinksysDMA2100Profile : DefaultProfile
{
public LinksysDMA2100Profile()
{
// Linksys DMA2100us does not need any transcoding of the formats we support statically
Name = "Linksys DMA2100";
Identification = new DeviceIdentification
{
ModelName = "DMA2100us"
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mp3,flac,m4a,wma",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "avi,mp4,mkv,ts,mpegts,m4v",
Type = DlnaProfileType.Video
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,43 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class MarantzProfile : DefaultProfile
{
public MarantzProfile()
{
Name = "Marantz";
SupportedMediaTypes = "Audio";
Identification = new DeviceIdentification
{
Manufacturer = @"Marantz",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "Marantz",
Match = HeaderMatchType.Substring
}
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "aac,mp3,wav,wma,flac",
Type = DlnaProfileType.Audio
},
};
ResponseProfiles = System.Array.Empty<ResponseProfile>();
}
}
}

@ -1,44 +0,0 @@
#pragma warning disable CS1591
using System;
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class MediaMonkeyProfile : DefaultProfile
{
public MediaMonkeyProfile()
{
Name = "MediaMonkey";
SupportedMediaTypes = "Audio";
Identification = new DeviceIdentification
{
FriendlyName = @"MediaMonkey",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "MediaMonkey",
Match = HeaderMatchType.Substring
}
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus,flac,m4a",
Type = DlnaProfileType.Audio
}
};
ResponseProfiles = Array.Empty<ResponseProfile>();
}
}
}

@ -1,222 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class PanasonicVieraProfile : DefaultProfile
{
public PanasonicVieraProfile()
{
Name = "Panasonic Viera";
Identification = new DeviceIdentification
{
FriendlyName = @"VIERA",
Manufacturer = "Panasonic",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "Panasonic MIL DLNA",
Match = HeaderMatchType.Substring
}
}
};
AddXmlRootAttribute("xmlns:pv", "http://www.pv.com/pvns/");
TimelineOffsetSeconds = 10;
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
AudioCodec = "ac3",
VideoCodec = "h264",
Type = DlnaProfileType.Video
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mpeg,mpg",
VideoCodec = "mpeg2video,mpeg4",
AudioCodec = "ac3,mp3,pcm_dvd",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mkv",
VideoCodec = "h264,mpeg2video",
AudioCodec = "aac,ac3,dca,mp3,mp2,pcm,dts",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "h264,mpeg2video",
AudioCodec = "aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,m4v",
VideoCodec = "h264",
AudioCodec = "aac,ac3,mp3,pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mov",
VideoCodec = "h264",
AudioCodec = "aac,pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mpeg4",
AudioCodec = "pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "flv",
VideoCodec = "h264",
AudioCodec = "aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp4",
AudioCodec = "aac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitDepth,
Value = "8",
IsRequired = false
}
}
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
},
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.External
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Type = DlnaProfileType.Video,
Container = "ts,mpegts",
OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
MimeType = "video/vnd.dlna.mpeg-tts"
},
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
}
}
}

@ -1,225 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class PopcornHourProfile : DefaultProfile
{
public PopcornHourProfile()
{
Name = "Popcorn Hour";
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "mp4",
Type = DlnaProfileType.Video,
AudioCodec = "aac",
VideoCodec = "h264"
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mp4,mov,m4v",
Type = DlnaProfileType.Video,
VideoCodec = "h264,mpeg4",
AudioCodec = "aac"
},
new DirectPlayProfile
{
Container = "ts,mpegts",
Type = DlnaProfileType.Video,
VideoCodec = "h264",
AudioCodec = "aac,ac3,eac3,mp3,mp2,pcm"
},
new DirectPlayProfile
{
Container = "asf,wmv",
Type = DlnaProfileType.Video,
VideoCodec = "wmv3,vc1",
AudioCodec = "wmav2,wmapro"
},
new DirectPlayProfile
{
Container = "avi",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg4,msmpeg4",
AudioCodec = "mp3,ac3,eac3,mp2,pcm"
},
new DirectPlayProfile
{
Container = "mkv",
Type = DlnaProfileType.Video,
VideoCodec = "h264",
AudioCodec = "aac,mp3,ac3,eac3,mp2,pcm"
},
new DirectPlayProfile
{
Container = "aac,mp3,flac,ogg,wma,wav",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg,gif,bmp,png",
Type = DlnaProfileType.Photo
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition(ProfileConditionType.EqualsAny, ProfileConditionValue.VideoProfile, "baseline|constrained baseline"),
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.IsAnamorphic,
Value = "true",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.IsAnamorphic,
Value = "true",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.Audio,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.Audio,
Codec = "mp3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioBitrate,
Value = "320000",
IsRequired = false
}
}
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,367 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class SamsungSmartTvProfile : DefaultProfile
{
public SamsungSmartTvProfile()
{
Name = "Samsung Smart TV";
EnableAlbumArtInDidl = true;
// Without this, older samsungs fail to browse
EnableSingleAlbumArtLimit = true;
Identification = new DeviceIdentification
{
ModelUrl = "samsung.com",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = @"SEC_",
Match = HeaderMatchType.Substring
}
}
};
AddXmlRootAttribute("xmlns:sec", "http://www.sec.co.kr/");
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
AudioCodec = "ac3",
VideoCodec = "h264",
Type = DlnaProfileType.Video,
EstimateContentLength = false
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "h264,mpeg4,mjpeg",
AudioCodec = "mp3,ac3,wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "h264,mpeg4,mjpeg",
AudioCodec = "mp3,ac3,dca,dts",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mkv",
VideoCodec = "h264,mpeg4,mjpeg4",
AudioCodec = "mp3,ac3,dca,aac,dts",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,m4v",
VideoCodec = "h264,mpeg4",
AudioCodec = "mp3,aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "3gp",
VideoCodec = "h264,mpeg4",
AudioCodec = "aac,he-aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpg,mpeg",
VideoCodec = "mpeg1video,mpeg2video,h264",
AudioCodec = "ac3,mp2,mp3,aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "vro,vob",
VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "ac3,mp2,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "mpeg2video,h264,vc1",
AudioCodec = "ac3,aac,mp3,eac3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3",
AudioCodec = "wmav2,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3,flac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "mpeg2video",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "30720000"
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Codec = "mpeg4",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "8192000"
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "37500000"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Codec = "wmv2,wmv3,vc1",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "25600000"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "wmav2,dca,aac,mp3,dts",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "avi",
MimeType = "video/x-msvideo",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mkv",
MimeType = "video/x-mkv",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "flac",
MimeType = "audio/x-flac",
Type = DlnaProfileType.Audio
},
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
},
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.External,
DidlMode = "CaptionInfoEx"
}
};
}
}
}

@ -1,121 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class SharpSmartTvProfile : DefaultProfile
{
public SharpSmartTvProfile()
{
Name = "Sharp Smart TV";
RequiresPlainFolders = true;
RequiresPlainVideoItems = true;
Identification = new DeviceIdentification
{
Manufacturer = "Sharp",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "Sharp",
Match = HeaderMatchType.Substring
}
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video,
AudioCodec = "ac3,aac,mp3,dts,dca",
VideoCodec = "h264",
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "m4v,mkv,avi,mov,mp4",
VideoCodec = "h264,mpeg4",
AudioCodec = "aac,mp3,ac3,dts,dca",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf,wmv",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpg,mpeg",
VideoCodec = "mpeg2video",
AudioCodec = "mp3,aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "flv",
VideoCodec = "h264",
AudioCodec = "mp3,aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3,wav",
Type = DlnaProfileType.Audio
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
},
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.External
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,366 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class SonyBravia2010Profile : DefaultProfile
{
public SonyBravia2010Profile()
{
Name = "Sony Bravia (2010)";
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*",
Manufacturer = "Sony",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*",
Match = HeaderMatchType.Regex
}
}
};
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
AlbumArtPn = "JPEG_TN";
ModelName = "Windows Media Player Sharing";
ModelNumber = "3.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
SonyAggregationFlags = "10";
ProtocolInfo =
"http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000";
EnableSingleAlbumArtLimit = true;
EnableAlbumArtInDidl = true;
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3",
Type = DlnaProfileType.Video,
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg1video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "192"
},
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.VideoTimestamp,
Value = "Valid"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "188"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Codec = "mpeg2video",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000"
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
},
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.AudioProfile,
Value = "he-aac"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,389 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class SonyBravia2011Profile : DefaultProfile
{
public SonyBravia2011Profile()
{
Name = "Sony Bravia (2011)";
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*",
Manufacturer = "Sony",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*",
Match = HeaderMatchType.Regex
}
}
};
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
AlbumArtPn = "JPEG_TN";
ModelName = "Windows Media Player Sharing";
ModelNumber = "3.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
SonyAggregationFlags = "10";
EnableSingleAlbumArtLimit = true;
EnableAlbumArtInDidl = true;
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3",
Type = DlnaProfileType.Video,
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg2video",
AudioCodec = "mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,m4v",
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg1video",
AudioCodec = "mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3,vc1",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "192"
},
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.VideoTimestamp,
Value = "Valid"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "188"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Codec = "mpeg2video",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000"
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
},
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.AudioProfile,
Value = "he-aac"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,307 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class SonyBravia2012Profile : DefaultProfile
{
public SonyBravia2012Profile()
{
Name = "Sony Bravia (2012)";
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*",
Manufacturer = "Sony",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*",
Match = HeaderMatchType.Regex
}
}
};
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
AlbumArtPn = "JPEG_TN";
ModelName = "Windows Media Player Sharing";
ModelNumber = "3.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
SonyAggregationFlags = "10";
EnableSingleAlbumArtLimit = true;
EnableAlbumArtInDidl = true;
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3",
Type = DlnaProfileType.Video,
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg2video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,m4v",
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mpeg4",
AudioCodec = "ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg1video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3,vc1",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "192"
},
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.VideoTimestamp,
Value = "Valid"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "188"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,324 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class SonyBravia2013Profile : DefaultProfile
{
public SonyBravia2013Profile()
{
Name = "Sony Bravia (2013)";
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-[0-9]{2}[WR][5689][0-9]{2}A.*",
Manufacturer = "Sony",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-[0-9]{2}[WR][5689][0-9]{2}A.*",
Match = HeaderMatchType.Regex
}
}
};
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
AlbumArtPn = "JPEG_TN";
ModelName = "Windows Media Player Sharing";
ModelNumber = "3.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
SonyAggregationFlags = "10";
EnableSingleAlbumArtLimit = true;
EnableAlbumArtInDidl = true;
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3",
Type = DlnaProfileType.Video,
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,eac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg2video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,m4v",
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,eac3,aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mov",
VideoCodec = "h264,mpeg4,mjpeg",
AudioCodec = "ac3,eac3,aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mkv",
VideoCodec = "h264,mpeg4,vp8",
AudioCodec = "ac3,eac3,aac,mp3,mp2,pcm,vorbis",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mpeg4",
AudioCodec = "ac3,eac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mjpeg",
AudioCodec = "pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg1video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3,vc1",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp4",
AudioCodec = "aac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "wav",
AudioCodec = "pcm",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "192"
},
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.VideoTimestamp,
Value = "Valid"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "188"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,324 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class SonyBravia2014Profile : DefaultProfile
{
public SonyBravia2014Profile()
{
Name = "Sony Bravia (2014)";
Identification = new DeviceIdentification
{
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",
Headers = new[]
{
new 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 = HeaderMatchType.Regex
}
}
};
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
AlbumArtPn = "JPEG_TN";
ModelName = "Windows Media Player Sharing";
ModelNumber = "3.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
SonyAggregationFlags = "10";
EnableSingleAlbumArtLimit = true;
EnableAlbumArtInDidl = true;
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3",
Type = DlnaProfileType.Video,
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,eac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg2video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,m4v",
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,eac3,aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mov",
VideoCodec = "h264,mpeg4,mjpeg",
AudioCodec = "ac3,eac3,aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mkv",
VideoCodec = "h264,mpeg4,vp8",
AudioCodec = "ac3,eac3,aac,mp3,mp2,pcm,vorbis",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mpeg4",
AudioCodec = "ac3,eac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mjpeg",
AudioCodec = "pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg1video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3,vc1",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp4",
AudioCodec = "aac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "wav",
AudioCodec = "pcm",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "192"
},
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.VideoTimestamp,
Value = "Valid"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.PacketLength,
Value = "188"
}
}
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,269 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class SonyPs3Profile : DefaultProfile
{
public SonyPs3Profile()
{
Name = "Sony PlayStation 3";
Identification = new DeviceIdentification
{
FriendlyName = "PLAYSTATION 3",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = @"PLAYSTATION 3",
Match = HeaderMatchType.Substring
},
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @"PLAYSTATION 3",
Match = HeaderMatchType.Substring
}
}
};
AlbumArtPn = "JPEG_TN";
SonyAggregationFlags = "10";
EnableSingleAlbumArtLimit = true;
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "avi",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg4",
AudioCodec = "mp2,mp3"
},
new DirectPlayProfile
{
Container = "ts,mpegts",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,h264",
AudioCodec = "aac,ac3,mp2"
},
new DirectPlayProfile
{
Container = "mpeg",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "mp2"
},
new DirectPlayProfile
{
Container = "mp4",
Type = DlnaProfileType.Video,
VideoCodec = "h264,mpeg4",
AudioCodec = "aac,ac3"
},
new DirectPlayProfile
{
Container = "aac,mp3,wav",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg,png,gif,bmp,tiff",
Type = DlnaProfileType.Photo
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "aac,ac3,mp2",
Type = DlnaProfileType.Video
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "15360000",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioBitrate,
Value = "640000",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "wmapro",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.AudioProfile,
Value = "he-aac",
IsRequired = false
}
}
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "mp4,mov",
AudioCodec = "aac",
MimeType = "video/mp4",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "avi",
MimeType = "video/divx",
OrgPn = "AVI",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "wav",
MimeType = "audio/wav",
Type = DlnaProfileType.Audio
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,278 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class SonyPs4Profile : DefaultProfile
{
public SonyPs4Profile()
{
Name = "Sony PlayStation 4";
Identification = new DeviceIdentification
{
FriendlyName = "PLAYSTATION 4",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = @"PLAYSTATION 4",
Match = HeaderMatchType.Substring
},
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @"PLAYSTATION 4",
Match = HeaderMatchType.Substring
}
}
};
AlbumArtPn = "JPEG_TN";
SonyAggregationFlags = "10";
EnableSingleAlbumArtLimit = true;
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "avi",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg4",
AudioCodec = "mp2,mp3"
},
new DirectPlayProfile
{
Container = "ts,mpegts",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,h264",
AudioCodec = "aac,ac3,mp2"
},
new DirectPlayProfile
{
Container = "mpeg",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "mp2"
},
new DirectPlayProfile
{
Container = "mp4,mkv,m4v",
Type = DlnaProfileType.Video,
VideoCodec = "h264,mpeg4",
AudioCodec = "aac,ac3"
},
new DirectPlayProfile
{
Container = "aac,mp3,wav",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg,png,gif,bmp,tiff",
Type = DlnaProfileType.Photo
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio,
// Transcoded audio won't be playable at all without this
TranscodeSeekInfo = TranscodeSeekInfo.Bytes
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "aac,ac3,mp2",
Type = DlnaProfileType.Video
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "15360000",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "ac3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioBitrate,
Value = "640000",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "wmapro",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.AudioProfile,
Value = "he-aac",
IsRequired = false
}
}
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "mp4,mov",
AudioCodec = "aac",
MimeType = "video/mp4",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "avi",
MimeType = "video/divx",
OrgPn = "AVI",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "wav",
MimeType = "audio/wav",
Type = DlnaProfileType.Audio
},
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,266 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class WdtvLiveProfile : DefaultProfile
{
public WdtvLiveProfile()
{
Name = "WDTV Live";
TimelineOffsetSeconds = 5;
IgnoreTranscodeByteRangeRequests = true;
Identification = new DeviceIdentification
{
ModelName = "WD TV",
Headers = new[]
{
new HttpHeaderInfo { Name = "User-Agent", Value = "alphanetworks", Match = HeaderMatchType.Substring },
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "ALPHA Networks",
Match = HeaderMatchType.Substring
}
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio,
AudioCodec = "mp3"
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video,
VideoCodec = "h264",
AudioCodec = "aac"
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "avi",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
AudioCodec = "ac3,eac3,dca,mp2,mp3,pcm,dts"
},
new DirectPlayProfile
{
Container = "mpeg",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "ac3,eac3,dca,mp2,mp3,pcm,dts"
},
new DirectPlayProfile
{
Container = "mkv",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
AudioCodec = "ac3,eac3,dca,aac,mp2,mp3,pcm,dts"
},
new DirectPlayProfile
{
Container = "ts,m2ts,mpegts",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,h264,vc1",
AudioCodec = "ac3,eac3,dca,mp2,mp3,aac,dts"
},
new DirectPlayProfile
{
Container = "mp4,mov,m4v",
Type = DlnaProfileType.Video,
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,eac3,aac,mp2,mp3,dca,dts"
},
new DirectPlayProfile
{
Container = "asf",
Type = DlnaProfileType.Video,
VideoCodec = "vc1",
AudioCodec = "wmav2,wmapro"
},
new DirectPlayProfile
{
Container = "asf",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg2video",
AudioCodec = "mp2,ac3"
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp2,mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp4",
AudioCodec = "mp4",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "flac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "ogg",
AudioCodec = "vorbis",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Type = DlnaProfileType.Photo,
Container = "jpeg,png,gif,bmp,tiff"
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "ts,mpegts",
OrgPn = "MPEG_TS_SD_NA",
Type = DlnaProfileType.Video
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.External
},
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
},
new SubtitleProfile
{
Format = "sub",
Method = SubtitleDeliveryMethod.Embed
},
new SubtitleProfile
{
Format = "subrip",
Method = SubtitleDeliveryMethod.Embed
},
new SubtitleProfile
{
Format = "idx",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -1,372 +0,0 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
{
[System.Xml.Serialization.XmlRoot("Profile")]
public class XboxOneProfile : DefaultProfile
{
public XboxOneProfile()
{
Name = "Xbox One";
TimelineOffsetSeconds = 40;
Identification = new DeviceIdentification
{
ModelName = "Xbox One",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "FriendlyName.DLNA.ORG", Value = "XboxOne", Match = HeaderMatchType.Substring
},
new HttpHeaderInfo
{
Name = "User-Agent", Value = "NSPlayer/12", Match = HeaderMatchType.Substring
}
}
};
var videoProfile = "high|main|baseline|constrained baseline";
var videoLevel = "41";
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "jpeg",
VideoCodec = "jpeg",
Type = DlnaProfileType.Photo
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "aac",
Type = DlnaProfileType.Video
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts,mpegts",
VideoCodec = "h264,mpeg2video,hevc",
AudioCodec = "ac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mpeg4",
AudioCodec = "ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "h264",
AudioCodec = "aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,mov,mkv,m4v",
VideoCodec = "h264,mpeg4,mpeg2video,hevc",
AudioCodec = "aac,ac3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3,vc1",
AudioCodec = "wmav2,wmapro",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Video,
Container = "mp4,mov",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.Has64BitOffsets,
Value = "false",
IsRequired = false
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
Codec = "mpeg4",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.IsAnamorphic,
Value = "true",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitDepth,
Value = "8",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "5120000",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.IsAnamorphic,
Value = "true",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitDepth,
Value = "8",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = videoLevel,
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.EqualsAny,
Property = ProfileConditionValue.VideoProfile,
Value = videoProfile,
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Codec = "wmv2,wmv3,vc1",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.IsAnamorphic,
Value = "true",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitDepth,
Value = "8",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "15360000",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.Video,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.IsAnamorphic,
Value = "true",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitDepth,
Value = "8",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "ac3,wmav2,wmapro",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudio,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.AudioProfile,
Value = "lc",
IsRequired = false
}
}
}
};
ResponseProfiles = new[]
{
new ResponseProfile
{
Container = "avi",
MimeType = "video/avi",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
};
SubtitleProfiles = new[]
{
new SubtitleProfile
{
Format = "srt",
Method = SubtitleDeliveryMethod.Embed
}
};
}
}
}

@ -6,8 +6,8 @@ using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Diacritics.Extensions;
using Emby.Dlna.Didl;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Configuration;
using Microsoft.Extensions.Logging;

@ -32,7 +32,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

@ -395,7 +395,13 @@ namespace Emby.Drawing
public string GetImageBlurHash(string path)
{
var size = GetImageDimensions(path);
if (size.Width <= 0 || size.Height <= 0)
return GetImageBlurHash(path, size);
}
/// <inheritdoc />
public string GetImageBlurHash(string path, ImageDimensions imageDimensions)
{
if (imageDimensions.Width <= 0 || imageDimensions.Height <= 0)
{
return string.Empty;
}
@ -403,8 +409,8 @@ namespace Emby.Drawing
// We want tiles to be as close to square as possible, and to *mostly* keep under 16 tiles for performance.
// One tile is (width / xComp) x (height / yComp) pixels, which means that ideally yComp = xComp * height / width.
// See more at https://github.com/woltapp/blurhash/#how-do-i-pick-the-number-of-x-and-y-components
float xCompF = MathF.Sqrt(16.0f * size.Width / size.Height);
float yCompF = xCompF * size.Height / size.Width;
float xCompF = MathF.Sqrt(16.0f * imageDimensions.Width / imageDimensions.Height);
float yCompF = xCompF * imageDimensions.Height / imageDimensions.Width;
int xComp = Math.Min((int)xCompF + 1, 9);
int yComp = Math.Min((int)yCompF + 1, 9);
@ -439,47 +445,46 @@ namespace Emby.Drawing
.ToString("N", CultureInfo.InvariantCulture);
}
private async Task<(string Path, DateTime DateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
private Task<(string Path, DateTime DateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
{
var inputFormat = Path.GetExtension(originalImagePath)
.TrimStart('.')
.Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
var inputFormat = Path.GetExtension(originalImagePath.AsSpan()).TrimStart('.').ToString();
// These are just jpg files renamed as tbn
if (string.Equals(inputFormat, "tbn", StringComparison.OrdinalIgnoreCase))
{
return (originalImagePath, dateModified);
}
if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat))
{
try
{
string filename = (originalImagePath + dateModified.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture);
string cacheExtension = _mediaEncoder.SupportsEncoder("libwebp") ? ".webp" : ".png";
var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension);
var file = _fileSystem.GetFileInfo(outputPath);
if (!file.Exists)
{
await _mediaEncoder.ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath);
}
else
{
dateModified = file.LastWriteTimeUtc;
}
originalImagePath = outputPath;
}
catch (Exception ex)
{
_logger.LogError(ex, "Image conversion failed for {Path}", originalImagePath);
}
}
return (originalImagePath, dateModified);
return Task.FromResult((originalImagePath, dateModified));
}
// TODO _mediaEncoder.ConvertImage is not implemented
// if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat))
// {
// try
// {
// string filename = (originalImagePath + dateModified.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture);
//
// string cacheExtension = _mediaEncoder.SupportsEncoder("libwebp") ? ".webp" : ".png";
// var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension);
//
// var file = _fileSystem.GetFileInfo(outputPath);
// if (!file.Exists)
// {
// await _mediaEncoder.ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
// dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath);
// }
// else
// {
// dateModified = file.LastWriteTimeUtc;
// }
//
// originalImagePath = outputPath;
// }
// catch (Exception ex)
// {
// _logger.LogError(ex, "Image conversion failed for {Path}", originalImagePath);
// }
// }
return Task.FromResult((originalImagePath, dateModified));
}
/// <summary>

@ -3,7 +3,7 @@ namespace Emby.Naming.AudioBook
/// <summary>
/// Data object for passing result of audiobook part/chapter extraction.
/// </summary>
public struct AudioBookFilePathParserResult
public record struct AudioBookFilePathParserResult
{
/// <summary>
/// Gets or sets optional number of path extracted from audiobook filename.

@ -48,7 +48,6 @@ namespace Emby.Naming.Common
".mkv",
".mk3d",
".mov",
".mp2",
".mp4",
".mpe",
".mpeg",
@ -315,7 +314,7 @@ namespace Emby.Naming.Common
// This isn't a Kodi naming rule, but the expression below causes false positives,
// so we make sure this one gets tested first.
// "Foo Bar 889"
new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\/x]*$")
new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,4})(-(?<endingepnumber>[0-9]{2,4}))*[^\\\/x]*$")
{
IsNamed = true
},

@ -36,7 +36,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Naming</PackageId>
<VersionPrefix>10.8.0</VersionPrefix>
<VersionPrefix>10.9.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
@ -52,7 +52,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

@ -28,7 +28,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

@ -15,7 +15,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="TagLibSharp" Version="2.2.0" />
<PackageReference Include="TagLibSharp" Version="2.3.0" />
</ItemGroup>
<PropertyGroup>
@ -30,7 +30,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

@ -210,10 +210,7 @@ namespace Emby.Server.Implementations.AppBase
/// <exception cref="ArgumentNullException"><c>newConfiguration</c> is <c>null</c>.</exception>
public virtual void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration)
{
if (newConfiguration == null)
{
throw new ArgumentNullException(nameof(newConfiguration));
}
ArgumentNullException.ThrowIfNull(newConfiguration);
ValidateCachePath(newConfiguration);
@ -365,11 +362,7 @@ namespace Emby.Server.Implementations.AppBase
validatingStore.Validate(currentConfiguration, configuration);
}
NamedConfigurationUpdating?.Invoke(this, new ConfigurationUpdateEventArgs
{
Key = key,
NewConfiguration = configuration
});
NamedConfigurationUpdating?.Invoke(this, new ConfigurationUpdateEventArgs(key, configuration));
_configurations.AddOrUpdate(key, configuration, (_, _) => configuration);
@ -391,11 +384,13 @@ namespace Emby.Server.Implementations.AppBase
/// <param name="configuration">The old configuration.</param>
protected virtual void OnNamedConfigurationUpdated(string key, object configuration)
{
NamedConfigurationUpdated?.Invoke(this, new ConfigurationUpdateEventArgs
{
Key = key,
NewConfiguration = configuration
});
NamedConfigurationUpdated?.Invoke(this, new ConfigurationUpdateEventArgs(key, configuration));
}
/// <inheritdoc />
public ConfigurationStore[] GetConfigurationStores()
{
return _configurationStores;
}
/// <inheritdoc />

@ -83,6 +83,7 @@ using MediaBrowser.Controller.SyncPlay;
using MediaBrowser.Controller.TV;
using MediaBrowser.LocalMetadata.Savers;
using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.MediaEncoding.Subtitles;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
@ -111,7 +112,7 @@ namespace Emby.Server.Implementations
/// <summary>
/// Class CompositionRoot.
/// </summary>
public abstract class ApplicationHost : IServerApplicationHost, IDisposable
public abstract class ApplicationHost : IServerApplicationHost, IAsyncDisposable, IDisposable
{
/// <summary>
/// The environment variable prefixes to log at server startup.
@ -629,12 +630,11 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
serviceCollection.AddScoped<ISessionContext, SessionContext>();
serviceCollection.AddSingleton<IAuthService, AuthService>();
serviceCollection.AddSingleton<IQuickConnect, QuickConnectManager>();
serviceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
serviceCollection.AddSingleton<ISubtitleParser, SubtitleEditParser>();
serviceCollection.AddSingleton<ISubtitleEncoder, SubtitleEncoder>();
serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
@ -1114,13 +1114,13 @@ namespace Emby.Server.Implementations
}
/// <inheritdoc/>
public string GetApiUrlForLocalAccess(bool allowHttps = true)
public string GetApiUrlForLocalAccess(IPObject hostname = null, bool allowHttps = true)
{
// With an empty source, the port will be null
string smart = NetManager.GetBindInterface(string.Empty, out _);
var smart = NetManager.GetBindInterface(hostname ?? IPHost.None, out _);
var scheme = !allowHttps ? Uri.UriSchemeHttp : null;
int? port = !allowHttps ? HttpPort : null;
return GetLocalApiUrl(smart.Trim('/'), scheme, port);
return GetLocalApiUrl(smart, scheme, port);
}
/// <inheritdoc/>
@ -1134,11 +1134,13 @@ namespace Emby.Server.Implementations
// NOTE: If no BaseUrl is set then UriBuilder appends a trailing slash, but if there is no BaseUrl it does
// not. For consistency, always trim the trailing slash.
scheme ??= ListenWithHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
var isHttps = string.Equals(scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase);
return new UriBuilder
{
Scheme = scheme ?? (ListenWithHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp),
Scheme = scheme,
Host = hostname,
Port = port ?? (ListenWithHttps ? HttpsPort : HttpPort),
Port = port ?? (isHttps ? HttpsPort : HttpPort),
Path = ConfigurationManager.GetNetworkConfiguration().BaseUrl
}.ToString().TrimEnd('/');
}
@ -1230,5 +1232,49 @@ namespace Emby.Server.Implementations
_disposed = true;
}
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore().ConfigureAwait(false);
Dispose(false);
GC.SuppressFinalize(this);
}
/// <summary>
/// Used to perform asynchronous cleanup of managed resources or for cascading calls to <see cref="DisposeAsync"/>.
/// </summary>
/// <returns>A ValueTask.</returns>
protected virtual async ValueTask DisposeAsyncCore()
{
var type = GetType();
Logger.LogInformation("Disposing {Type}", type.Name);
foreach (var (part, _) in _disposableParts)
{
var partType = part.GetType();
if (partType == type)
{
continue;
}
Logger.LogInformation("Disposing {Type}", partType.Name);
try
{
part.Dispose();
}
catch (Exception ex)
{
Logger.LogError(ex, "Error disposing {Type}", partType.Name);
}
}
// used for closing websockets
foreach (var session in _sessionManager.Sessions)
{
await session.DisposeAsync().ConfigureAwait(false);
}
}
}
}

@ -1188,10 +1188,7 @@ namespace Emby.Server.Implementations.Channels
internal IChannel GetChannelProvider(Channel channel)
{
if (channel == null)
{
throw new ArgumentNullException(nameof(channel));
}
ArgumentNullException.ThrowIfNull(channel);
var result = GetAllChannels()
.FirstOrDefault(i => GetInternalChannelId(i.Name).Equals(channel.ChannelId) || string.Equals(i.Name, channel.Name, StringComparison.OrdinalIgnoreCase));

@ -54,10 +54,7 @@ namespace Emby.Server.Implementations.Data
public static void RunQueries(this SQLiteDatabaseConnection connection, string[] queries)
{
if (queries == null)
{
throw new ArgumentNullException(nameof(queries));
}
ArgumentNullException.ThrowIfNull(queries);
connection.RunInTransaction(conn =>
{

@ -11,7 +11,6 @@ using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading;
using Diacritics.Extensions;
using Emby.Server.Implementations.Playlists;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
@ -171,7 +170,15 @@ namespace Emby.Server.Implementations.Data
"CodecTimeBase",
"ColorPrimaries",
"ColorSpace",
"ColorTransfer"
"ColorTransfer",
"DvVersionMajor",
"DvVersionMinor",
"DvProfile",
"DvLevel",
"RpuPresentFlag",
"ElPresentFlag",
"BlPresentFlag",
"DvBlSignalCompatibilityId"
};
private static readonly string _mediaStreamSaveColumnsInsertQuery =
@ -342,7 +349,7 @@ namespace Emby.Server.Implementations.Data
public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager)
{
const string CreateMediaStreamsTableCommand
= "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, ColorPrimaries TEXT NULL, ColorSpace TEXT NULL, ColorTransfer TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
= "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, ColorPrimaries TEXT NULL, ColorSpace TEXT NULL, ColorTransfer TEXT NULL, DvVersionMajor INT NULL, DvVersionMinor INT NULL, DvProfile INT NULL, DvLevel INT NULL, RpuPresentFlag INT NULL, ElPresentFlag INT NULL, BlPresentFlag INT NULL, DvBlSignalCompatibilityId INT NULL, PRIMARY KEY (ItemId, StreamIndex))";
const string CreateMediaAttachmentsTableCommand
= "create table if not exists mediaattachments (ItemId GUID, AttachmentIndex INT, Codec TEXT, CodecTag TEXT NULL, Comment TEXT NULL, Filename TEXT NULL, MIMEType TEXT NULL, PRIMARY KEY (ItemId, AttachmentIndex))";
@ -556,6 +563,15 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "MediaStreams", "ColorPrimaries", "TEXT", existingColumnNames);
AddColumn(db, "MediaStreams", "ColorSpace", "TEXT", existingColumnNames);
AddColumn(db, "MediaStreams", "ColorTransfer", "TEXT", existingColumnNames);
AddColumn(db, "MediaStreams", "DvVersionMajor", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "DvVersionMinor", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "DvProfile", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "DvLevel", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "RpuPresentFlag", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "ElPresentFlag", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "BlPresentFlag", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "DvBlSignalCompatibilityId", "INT", existingColumnNames);
},
TransactionMode);
@ -567,10 +583,7 @@ namespace Emby.Server.Implementations.Data
public void SaveImages(BaseItem item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
ArgumentNullException.ThrowIfNull(item);
CheckDisposed();
@ -601,10 +614,7 @@ namespace Emby.Server.Implementations.Data
/// </exception>
public void SaveItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
{
if (items == null)
{
throw new ArgumentNullException(nameof(items));
}
ArgumentNullException.ThrowIfNull(items);
cancellationToken.ThrowIfCancellationRequested();
@ -2069,10 +2079,7 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException(nameof(id));
}
if (chapters == null)
{
throw new ArgumentNullException(nameof(chapters));
}
ArgumentNullException.ThrowIfNull(chapters);
var idBlob = id.ToByteArray();
@ -2404,7 +2411,7 @@ namespace Emby.Server.Implementations.Data
}
// genres, tags, studios, person, year?
builder.Append("+ (Select count(1) * 10 from ItemValues where ItemId=Guid and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId))");
builder.Append("+ (Select count(1) * 10 from ItemValues where ItemId=Guid and CleanValue in (select CleanValue from ItemValues where ItemId=@SimilarItemId))");
if (item is MusicArtist)
{
@ -2541,10 +2548,7 @@ namespace Emby.Server.Implementations.Data
public int GetCount(InternalItemsQuery query)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
ArgumentNullException.ThrowIfNull(query);
CheckDisposed();
@ -2597,10 +2601,7 @@ namespace Emby.Server.Implementations.Data
public List<BaseItem> GetItemList(InternalItemsQuery query)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
ArgumentNullException.ThrowIfNull(query);
CheckDisposed();
@ -2778,10 +2779,7 @@ namespace Emby.Server.Implementations.Data
public QueryResult<BaseItem> GetItems(InternalItemsQuery query)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
ArgumentNullException.ThrowIfNull(query);
CheckDisposed();
@ -3059,12 +3057,12 @@ namespace Emby.Server.Implementations.Data
if (string.Equals(name, ItemSortBy.Artist, StringComparison.OrdinalIgnoreCase))
{
return "(select CleanValue from itemvalues where ItemId=Guid and Type=0 LIMIT 1)";
return "(select CleanValue from ItemValues where ItemId=Guid and Type=0 LIMIT 1)";
}
if (string.Equals(name, ItemSortBy.AlbumArtist, StringComparison.OrdinalIgnoreCase))
{
return "(select CleanValue from itemvalues where ItemId=Guid and Type=1 LIMIT 1)";
return "(select CleanValue from ItemValues where ItemId=Guid and Type=1 LIMIT 1)";
}
if (string.Equals(name, ItemSortBy.OfficialRating, StringComparison.OrdinalIgnoreCase))
@ -3074,7 +3072,7 @@ namespace Emby.Server.Implementations.Data
if (string.Equals(name, ItemSortBy.Studio, StringComparison.OrdinalIgnoreCase))
{
return "(select CleanValue from itemvalues where ItemId=Guid and Type=3 LIMIT 1)";
return "(select CleanValue from ItemValues where ItemId=Guid and Type=3 LIMIT 1)";
}
if (string.Equals(name, ItemSortBy.SeriesDatePlayed, StringComparison.OrdinalIgnoreCase))
@ -3147,16 +3145,18 @@ namespace Emby.Server.Implementations.Data
return ItemSortBy.IndexNumber;
}
if (string.Equals(name, ItemSortBy.SimilarityScore, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.SimilarityScore;
}
// Unknown SortBy, just sort by the SortName.
return ItemSortBy.SortName;
}
public List<Guid> GetItemIdsList(InternalItemsQuery query)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
ArgumentNullException.ThrowIfNull(query);
CheckDisposed();
@ -3847,7 +3847,7 @@ namespace Emby.Server.Implementations.Data
{
var paramName = "@ArtistIds" + index;
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
clauses.Add("(guid in (select itemid from ItemValues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
if (statement != null)
{
statement.TryBind(paramName, artistId);
@ -3868,7 +3868,7 @@ namespace Emby.Server.Implementations.Data
{
var paramName = "@ArtistIds" + index;
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=1))");
clauses.Add("(guid in (select itemid from ItemValues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=1))");
if (statement != null)
{
statement.TryBind(paramName, artistId);
@ -3889,7 +3889,7 @@ namespace Emby.Server.Implementations.Data
{
var paramName = "@ArtistIds" + index;
clauses.Add("((select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=0) AND (select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type=1))");
clauses.Add("((select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from ItemValues where ItemId=Guid and Type=0) AND (select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from ItemValues where ItemId=Guid and Type=1))");
if (statement != null)
{
statement.TryBind(paramName, artistId);
@ -3931,7 +3931,7 @@ namespace Emby.Server.Implementations.Data
{
var paramName = "@ExcludeArtistId" + index;
clauses.Add("(guid not in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
clauses.Add("(guid not in (select itemid from ItemValues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
if (statement != null)
{
statement.TryBind(paramName, artistId);
@ -3952,7 +3952,7 @@ namespace Emby.Server.Implementations.Data
{
var paramName = "@GenreId" + index;
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=2))");
clauses.Add("(guid in (select itemid from ItemValues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=2))");
if (statement != null)
{
statement.TryBind(paramName, genreId);
@ -3971,7 +3971,7 @@ namespace Emby.Server.Implementations.Data
var index = 0;
foreach (var item in query.Genres)
{
clauses.Add("@Genre" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=2)");
clauses.Add("@Genre" + index + " in (select CleanValue from ItemValues where ItemId=Guid and Type=2)");
if (statement != null)
{
statement.TryBind("@Genre" + index, GetCleanValue(item));
@ -3990,7 +3990,7 @@ namespace Emby.Server.Implementations.Data
var index = 0;
foreach (var item in tags)
{
clauses.Add("@Tag" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=4)");
clauses.Add("@Tag" + index + " in (select CleanValue from ItemValues where ItemId=Guid and Type=4)");
if (statement != null)
{
statement.TryBind("@Tag" + index, GetCleanValue(item));
@ -4009,7 +4009,7 @@ namespace Emby.Server.Implementations.Data
var index = 0;
foreach (var item in excludeTags)
{
clauses.Add("@ExcludeTag" + index + " not in (select CleanValue from itemvalues where ItemId=Guid and Type=4)");
clauses.Add("@ExcludeTag" + index + " not in (select CleanValue from ItemValues where ItemId=Guid and Type=4)");
if (statement != null)
{
statement.TryBind("@ExcludeTag" + index, GetCleanValue(item));
@ -4030,7 +4030,7 @@ namespace Emby.Server.Implementations.Data
{
var paramName = "@StudioId" + index;
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=3))");
clauses.Add("(guid in (select itemid from ItemValues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=3))");
if (statement != null)
{
@ -4509,7 +4509,7 @@ namespace Emby.Server.Implementations.Data
{
int index = 0;
string excludedTags = string.Join(',', query.ExcludeInheritedTags.Select(_ => paramName + index++));
whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + excludedTags + ")) is null)");
whereClauses.Add("((select CleanValue from ItemValues where ItemId=Guid and Type=6 and cleanvalue in (" + excludedTags + ")) is null)");
}
else
{
@ -4744,11 +4744,11 @@ namespace Emby.Server.Implementations.Data
';',
new string[]
{
"delete from itemvalues where type = 6",
"delete from ItemValues where type = 6",
"insert into itemvalues (ItemId, Type, Value, CleanValue) select ItemId, 6, Value, CleanValue from ItemValues where Type=4",
"insert into ItemValues (ItemId, Type, Value, CleanValue) select ItemId, 6, Value, CleanValue from ItemValues where Type=4",
@"insert into itemvalues (ItemId, Type, Value, CleanValue) select AncestorIds.itemid, 6, ItemValues.Value, ItemValues.CleanValue
@"insert into ItemValues (ItemId, Type, Value, CleanValue) select AncestorIds.itemid, 6, ItemValues.Value, ItemValues.CleanValue
FROM AncestorIds
LEFT JOIN ItemValues ON (AncestorIds.AncestorId = ItemValues.ItemId)
where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type = 4 "
@ -4816,10 +4816,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
public List<string> GetPeopleNames(InternalPeopleQuery query)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
ArgumentNullException.ThrowIfNull(query);
CheckDisposed();
@ -4859,10 +4856,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
public List<PersonInfo> GetPeople(InternalPeopleQuery query)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
ArgumentNullException.ThrowIfNull(query);
CheckDisposed();
@ -4913,6 +4907,7 @@ SELECT key FROM UserDatas WHERE isFavorite=@IsFavorite AND userId=@UserId)
AND Type = @InternalPersonType)");
statement?.TryBind("@IsFavorite", query.IsFavorite.Value);
statement?.TryBind("@InternalPersonType", typeof(Person).FullName);
statement?.TryBind("@UserId", query.User.InternalId);
}
if (!query.ItemId.Equals(default))
@ -4967,11 +4962,6 @@ AND Type = @InternalPersonType)");
statement?.TryBind("@NameContains", "%" + query.NameContains + "%");
}
if (query.User != null)
{
statement?.TryBind("@UserId", query.User.InternalId);
}
return whereClauses;
}
@ -4982,10 +4972,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentNullException(nameof(itemId));
}
if (ancestorIds == null)
{
throw new ArgumentNullException(nameof(ancestorIds));
}
ArgumentNullException.ThrowIfNull(ancestorIds);
CheckDisposed();
@ -5158,10 +5145,7 @@ AND Type = @InternalPersonType)");
private QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetItemValues(InternalItemsQuery query, int[] itemValueTypes, string returnType)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
ArgumentNullException.ThrowIfNull(query);
if (!query.Limit.HasValue)
{
@ -5514,10 +5498,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentNullException(nameof(itemId));
}
if (values == null)
{
throw new ArgumentNullException(nameof(values));
}
ArgumentNullException.ThrowIfNull(values);
CheckDisposed();
@ -5590,10 +5571,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentNullException(nameof(itemId));
}
if (people == null)
{
throw new ArgumentNullException(nameof(people));
}
ArgumentNullException.ThrowIfNull(people);
CheckDisposed();
@ -5693,10 +5671,7 @@ AND Type = @InternalPersonType)");
{
CheckDisposed();
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
ArgumentNullException.ThrowIfNull(query);
var cmdText = _mediaStreamSaveColumnsSelectQuery;
@ -5749,10 +5724,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentNullException(nameof(id));
}
if (streams == null)
{
throw new ArgumentNullException(nameof(streams));
}
ArgumentNullException.ThrowIfNull(streams);
cancellationToken.ThrowIfCancellationRequested();
@ -5763,7 +5735,7 @@ AND Type = @InternalPersonType)");
{
var itemIdBlob = id.ToByteArray();
// First delete chapters
// Delete existing mediastreams
db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob);
InsertMediaStreams(itemIdBlob, streams, db);
@ -5855,6 +5827,15 @@ AND Type = @InternalPersonType)");
statement.TryBind("@ColorPrimaries" + index, stream.ColorPrimaries);
statement.TryBind("@ColorSpace" + index, stream.ColorSpace);
statement.TryBind("@ColorTransfer" + index, stream.ColorTransfer);
statement.TryBind("@DvVersionMajor" + index, stream.DvVersionMajor);
statement.TryBind("@DvVersionMinor" + index, stream.DvVersionMinor);
statement.TryBind("@DvProfile" + index, stream.DvProfile);
statement.TryBind("@DvLevel" + index, stream.DvLevel);
statement.TryBind("@RpuPresentFlag" + index, stream.RpuPresentFlag);
statement.TryBind("@ElPresentFlag" + index, stream.ElPresentFlag);
statement.TryBind("@BlPresentFlag" + index, stream.BlPresentFlag);
statement.TryBind("@DvBlSignalCompatibilityId" + index, stream.DvBlSignalCompatibilityId);
}
statement.Reset();
@ -5867,10 +5848,10 @@ AND Type = @InternalPersonType)");
}
/// <summary>
/// Gets the chapter.
/// Gets the media stream.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>ChapterInfo.</returns>
/// <returns>MediaStream.</returns>
private MediaStream GetMediaStream(IReadOnlyList<ResultSetValue> reader)
{
var item = new MediaStream
@ -6026,6 +6007,46 @@ AND Type = @InternalPersonType)");
item.ColorTransfer = colorTransfer;
}
if (reader.TryGetInt32(35, out var dvVersionMajor))
{
item.DvVersionMajor = dvVersionMajor;
}
if (reader.TryGetInt32(36, out var dvVersionMinor))
{
item.DvVersionMinor = dvVersionMinor;
}
if (reader.TryGetInt32(37, out var dvProfile))
{
item.DvProfile = dvProfile;
}
if (reader.TryGetInt32(38, out var dvLevel))
{
item.DvLevel = dvLevel;
}
if (reader.TryGetInt32(39, out var rpuPresentFlag))
{
item.RpuPresentFlag = rpuPresentFlag;
}
if (reader.TryGetInt32(40, out var elPresentFlag))
{
item.ElPresentFlag = elPresentFlag;
}
if (reader.TryGetInt32(41, out var blPresentFlag))
{
item.BlPresentFlag = blPresentFlag;
}
if (reader.TryGetInt32(42, out var dvBlSignalCompatibilityId))
{
item.DvBlSignalCompatibilityId = dvBlSignalCompatibilityId;
}
if (item.Type == MediaStreamType.Subtitle)
{
item.LocalizedUndefined = _localization.GetLocalizedString("Undefined");
@ -6041,10 +6062,7 @@ AND Type = @InternalPersonType)");
{
CheckDisposed();
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
ArgumentNullException.ThrowIfNull(query);
var cmdText = _mediaAttachmentSaveColumnsSelectQuery;
@ -6086,10 +6104,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentException("Guid can't be empty.", nameof(id));
}
if (attachments == null)
{
throw new ArgumentNullException(nameof(attachments));
}
ArgumentNullException.ThrowIfNull(attachments);
cancellationToken.ThrowIfCancellationRequested();

@ -133,10 +133,7 @@ namespace Emby.Server.Implementations.Data
/// <inheritdoc />
public void SaveUserData(long userId, string key, UserItemData userData, CancellationToken cancellationToken)
{
if (userData == null)
{
throw new ArgumentNullException(nameof(userData));
}
ArgumentNullException.ThrowIfNull(userData);
if (userId <= 0)
{
@ -154,10 +151,7 @@ namespace Emby.Server.Implementations.Data
/// <inheritdoc />
public void SaveAllUserData(long userId, UserItemData[] userData, CancellationToken cancellationToken)
{
if (userData == null)
{
throw new ArgumentNullException(nameof(userData));
}
ArgumentNullException.ThrowIfNull(userData);
if (userId <= 0)
{
@ -304,10 +298,7 @@ namespace Emby.Server.Implementations.Data
public UserItemData GetUserData(long userId, List<string> keys)
{
if (keys == null)
{
throw new ArgumentNullException(nameof(keys));
}
ArgumentNullException.ThrowIfNull(keys);
if (keys.Count == 0)
{

@ -182,7 +182,7 @@ namespace Emby.Server.Implementations.Dto
if (options.ContainsField(ItemFields.People))
{
AttachPeople(dto, item);
AttachPeople(dto, item, user);
}
if (options.ContainsField(ItemFields.PrimaryImageAspectRatio))
@ -503,7 +503,8 @@ namespace Emby.Server.Implementations.Dto
/// </summary>
/// <param name="dto">The dto.</param>
/// <param name="item">The item.</param>
private void AttachPeople(BaseItemDto dto, BaseItem item)
/// <param name="user">The requesting user.</param>
private void AttachPeople(BaseItemDto dto, BaseItem item, User user = null)
{
// Ordering by person type to ensure actors and artists are at the front.
// This is taking advantage of the fact that they both begin with A
@ -560,6 +561,9 @@ namespace Emby.Server.Implementations.Dto
return null;
}
}).Where(i => i != null)
.Where(i => user == null ?
true :
i.IsVisible(user))
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.Select(x => x.First())
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
@ -1094,7 +1098,7 @@ namespace Emby.Server.Implementations.Dto
{
if (item is IHasTrailers hasTrailers)
{
dto.LocalTrailerCount = hasTrailers.GetTrailerCount();
dto.LocalTrailerCount = hasTrailers.LocalTrailers.Count;
}
else
{

@ -24,15 +24,15 @@
<ItemGroup>
<PackageReference Include="DiscUtils.Udf" Version="0.16.13" />
<PackageReference Include="Jellyfin.XmlTv" Version="10.6.2" />
<PackageReference Include="Jellyfin.XmlTv" Version="10.8.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.3" />
<PackageReference Include="Mono.Nat" Version="3.0.2" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.3" />
<PackageReference Include="sharpcompress" Version="0.30.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.9" />
<PackageReference Include="Mono.Nat" Version="3.0.3" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.4" />
<PackageReference Include="sharpcompress" Version="0.32.2" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" />
<PackageReference Include="DotNet.Glob" Version="3.1.3" />
</ItemGroup>
@ -60,7 +60,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

@ -1,60 +0,0 @@
#pragma warning disable CS1591
using System;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using Microsoft.AspNetCore.Http;
namespace Emby.Server.Implementations.HttpServer.Security
{
public class SessionContext : ISessionContext
{
private readonly IUserManager _userManager;
private readonly ISessionManager _sessionManager;
private readonly IAuthorizationContext _authContext;
public SessionContext(IUserManager userManager, IAuthorizationContext authContext, ISessionManager sessionManager)
{
_userManager = userManager;
_authContext = authContext;
_sessionManager = sessionManager;
}
public async Task<SessionInfo> GetSession(HttpContext requestContext)
{
var authorization = await _authContext.GetAuthorizationInfo(requestContext).ConfigureAwait(false);
var user = authorization.User;
return await _sessionManager.LogSessionActivity(
authorization.Client,
authorization.Version,
authorization.DeviceId,
authorization.Device,
requestContext.GetNormalizedRemoteIp().ToString(),
user).ConfigureAwait(false);
}
public Task<SessionInfo> GetSession(object requestContext)
{
return GetSession((HttpContext)requestContext);
}
public async Task<User?> GetUser(HttpContext requestContext)
{
var session = await GetSession(requestContext).ConfigureAwait(false);
return session.UserId.Equals(default)
? null
: _userManager.GetUserById(session.UserId);
}
public Task<User?> GetUser(object requestContext)
{
return GetUser(((HttpRequest)requestContext).HttpContext);
}
}
}

@ -11,7 +11,6 @@ using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.HttpServer
@ -19,7 +18,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Class WebSocketConnection.
/// </summary>
public class WebSocketConnection : IWebSocketConnection, IDisposable
public class WebSocketConnection : IWebSocketConnection
{
/// <summary>
/// The logger.
@ -36,6 +35,8 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary>
private readonly WebSocket _socket;
private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketConnection" /> class.
/// </summary>
@ -244,10 +245,39 @@ namespace Emby.Server.Implementations.HttpServer
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool dispose)
{
if (_disposed)
{
return;
}
if (dispose)
{
_socket.Dispose();
}
_disposed = true;
}
/// <inheritdoc />
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore().ConfigureAwait(false);
Dispose(false);
GC.SuppressFinalize(this);
}
/// <summary>
/// Used to perform asynchronous cleanup of managed resources or for cascading calls to <see cref="DisposeAsync"/>.
/// </summary>
/// <returns>A ValueTask.</returns>
protected virtual async ValueTask DisposeAsyncCore()
{
if (_socket.State == WebSocketState.Open)
{
await _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "System Shutdown", CancellationToken.None).ConfigureAwait(false);
}
_socket.Dispose();
}
}
}

@ -262,6 +262,10 @@ namespace Emby.Server.Implementations.IO
_logger.LogError(ex, "Reading the file size of the symlink at {Path} failed. Marking the file as not existing.", fileInfo.FullName);
result.Exists = false;
}
catch (UnauthorizedAccessException ex)
{
_logger.LogError(ex, "Reading the file at {Path} failed due to a permissions exception.", fileInfo.FullName);
}
}
}

@ -93,6 +93,7 @@ namespace Emby.Server.Implementations.Images
returnItems.Shuffle();
return returnItems;
}
returnItems = items
.Where(i => i.HasImage(ImageType.Primary))
.ToList();

@ -46,7 +46,6 @@ using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
using EpisodeInfo = Emby.Naming.TV.EpisodeInfo;
@ -282,10 +281,7 @@ namespace Emby.Server.Implementations.Library
public void RegisterItem(BaseItem item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
ArgumentNullException.ThrowIfNull(item);
if (item is IItemByName)
{
@ -312,10 +308,7 @@ namespace Emby.Server.Implementations.Library
public void DeleteItem(BaseItem item, DeleteOptions options, bool notifyParentItem)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
ArgumentNullException.ThrowIfNull(item);
var parent = item.GetOwner() ?? item.GetParent();
@ -324,10 +317,7 @@ namespace Emby.Server.Implementations.Library
public void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
ArgumentNullException.ThrowIfNull(item);
if (item.SourceType == SourceType.Channel)
{
@ -510,10 +500,7 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(key));
}
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
ArgumentNullException.ThrowIfNull(type);
string programDataPath = _configurationManager.ApplicationPaths.ProgramDataPath;
if (key.StartsWith(programDataPath, StringComparison.Ordinal))
@ -545,10 +532,7 @@ namespace Emby.Server.Implementations.Library
string collectionType = null,
LibraryOptions libraryOptions = null)
{
if (fileInfo == null)
{
throw new ArgumentNullException(nameof(fileInfo));
}
ArgumentNullException.ThrowIfNull(fileInfo);
var fullPath = fileInfo.FullName;
@ -1855,12 +1839,11 @@ namespace Emby.Server.Implementations.Library
/// <inheritdoc />
public async Task UpdateImagesAsync(BaseItem item, bool forceUpdate = false)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
ArgumentNullException.ThrowIfNull(item);
var outdated = forceUpdate ? item.ImageInfos.Where(i => i.Path != null).ToArray() : item.ImageInfos.Where(ImageNeedsRefresh).ToArray();
var outdated = forceUpdate
? item.ImageInfos.Where(i => i.Path != null).ToArray()
: item.ImageInfos.Where(ImageNeedsRefresh).ToArray();
// Skip image processing if current or live tv source
if (outdated.Length == 0 || item.SourceType != SourceType.Library)
{
@ -1883,7 +1866,7 @@ namespace Emby.Server.Implementations.Library
_logger.LogWarning("Cannot get image index for {ImagePath}", img.Path);
continue;
}
catch (Exception ex) when (ex is InvalidOperationException || ex is IOException)
catch (Exception ex) when (ex is InvalidOperationException or IOException)
{
_logger.LogWarning(ex, "Cannot fetch image from {ImagePath}", img.Path);
continue;
@ -1895,23 +1878,24 @@ namespace Emby.Server.Implementations.Library
}
}
ImageDimensions size;
try
{
ImageDimensions size = _imageProcessor.GetImageDimensions(item, image);
size = _imageProcessor.GetImageDimensions(item, image);
image.Width = size.Width;
image.Height = size.Height;
}
catch (Exception ex)
{
_logger.LogError(ex, "Cannot get image dimensions for {ImagePath}", image.Path);
size = new ImageDimensions(0, 0);
image.Width = 0;
image.Height = 0;
continue;
}
try
{
image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path);
image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path, size);
}
catch (Exception ex)
{
@ -2294,10 +2278,7 @@ namespace Emby.Server.Implementations.Library
string viewType,
string sortName)
{
if (parent == null)
{
throw new ArgumentNullException(nameof(parent));
}
ArgumentNullException.ThrowIfNull(parent);
var name = parent.Name;
var parentId = parent.Id;
@ -2450,6 +2431,12 @@ namespace Emby.Server.Implementations.Library
return RootFolder;
}
/// <inheritdoc />
public void QueueLibraryScan()
{
_taskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
}
/// <inheritdoc />
public int? GetSeasonNumberFromPath(string path)
=> SeasonPathParser.Parse(path, true, true).SeasonNumber;
@ -2520,7 +2507,7 @@ namespace Emby.Server.Implementations.Library
}
catch (Exception ex)
{
_logger.LogError(ex, "Error reading the episode informations with ffprobe. Episode: {EpisodeInfo}", episodeInfo.Path);
_logger.LogError(ex, "Error reading the episode information with ffprobe. Episode: {EpisodeInfo}", episodeInfo.Path);
}
var changed = false;
@ -2757,7 +2744,8 @@ namespace Emby.Server.Implementations.Library
public List<Person> GetPeopleItems(InternalPeopleQuery query)
{
return _itemRepository.GetPeopleNames(query).Select(i =>
return _itemRepository.GetPeopleNames(query)
.Select(i =>
{
try
{
@ -2768,7 +2756,12 @@ namespace Emby.Server.Implementations.Library
_logger.LogError(ex, "Error getting person");
return null;
}
}).Where(i => i != null).ToList();
})
.Where(i => i != null)
.Where(i => query.User == null ?
true :
i.IsVisible(query.User))
.ToList();
}
public List<string> GetPeopleNames(InternalPeopleQuery query)
@ -2840,10 +2833,12 @@ namespace Emby.Server.Implementations.Library
var existingNameCount = 1; // first numbered name will be 2
var virtualFolderPath = Path.Combine(rootFolderPath, name);
var originalName = name;
while (Directory.Exists(virtualFolderPath))
{
existingNameCount++;
virtualFolderPath = Path.Combine(rootFolderPath, name + " " + existingNameCount);
name = originalName + existingNameCount;
virtualFolderPath = Path.Combine(rootFolderPath, name);
}
var mediaPathInfos = options.PathInfos;
@ -2967,10 +2962,7 @@ namespace Emby.Server.Implementations.Library
private void AddMediaPathInternal(string virtualFolderName, MediaPathInfo pathInfo, bool saveLibraryOptions)
{
if (pathInfo == null)
{
throw new ArgumentNullException(nameof(pathInfo));
}
ArgumentNullException.ThrowIfNull(pathInfo);
var path = pathInfo.Path;
@ -3017,10 +3009,7 @@ namespace Emby.Server.Implementations.Library
public void UpdateMediaPath(string virtualFolderName, MediaPathInfo mediaPath)
{
if (mediaPath == null)
{
throw new ArgumentNullException(nameof(mediaPath));
}
ArgumentNullException.ThrowIfNull(mediaPath);
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);

@ -151,7 +151,11 @@ namespace Emby.Server.Implementations.Library
{
var mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user);
if (allowMediaProbe && mediaSources[0].Type != MediaSourceType.Placeholder && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Audio || i.Type == MediaStreamType.Video))
// If file is strm or main media stream is missing, force a metadata refresh with remote probing
if (allowMediaProbe && mediaSources[0].Type != MediaSourceType.Placeholder
&& (item.Path.EndsWith(".strm", StringComparison.OrdinalIgnoreCase)
|| (item.MediaType == MediaType.Video && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Video))
|| (item.MediaType == MediaType.Audio && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Audio))))
{
await item.RefreshMetadata(
new MetadataRefreshOptions(_directoryService)
@ -318,10 +322,7 @@ namespace Emby.Server.Implementations.Library
public List<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
ArgumentNullException.ThrowIfNull(item);
var hasMediaSources = (IHasMediaSources)item;

@ -13,11 +13,11 @@ namespace Emby.Server.Implementations.Library
{
public static int? GetDefaultAudioStreamIndex(IReadOnlyList<MediaStream> streams, IReadOnlyList<string> preferredLanguages, bool preferDefaultTrack)
{
var sortedStreams = GetSortedStreams(streams, MediaStreamType.Audio, preferredLanguages);
var sortedStreams = GetSortedStreams(streams, MediaStreamType.Audio, preferredLanguages).ToList();
if (preferDefaultTrack)
{
var defaultStream = streams.FirstOrDefault(i => i.IsDefault);
var defaultStream = sortedStreams.FirstOrDefault(i => i.IsDefault);
if (defaultStream != null)
{

@ -225,7 +225,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
return ResolveVideos<Episode>(parent, files, true, collectionType, true);
return ResolveVideos<Episode>(parent, files, false, collectionType, true);
}
return null;
@ -387,7 +387,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (!string.IsNullOrEmpty(item.Path))
{
// check for imdb id - we use full media path, as we can assume, that this will match in any use case (wither id in parent dir or in file name)
// check for imdb id - we use full media path, as we can assume, that this will match in any use case (either id in parent dir or in file name)
var imdbid = item.Path.AsSpan().GetAttributeValue("imdbid");
if (!string.IsNullOrWhiteSpace(imdbid))
@ -464,7 +464,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
var result = ResolveVideos<T>(parent, fileSystemEntries, SupportsMultiVersion, collectionType, parseName) ??
new MultiItemResolverResult();
if (result.Items.Count == 1)
var isPhotosCollection = string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)
|| string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase);
if (!isPhotosCollection && result.Items.Count == 1)
{
var videoPath = result.Items[0].Path;
var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(videoPath, i.Name));

@ -91,10 +91,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
internal static bool IsImageFile(string path, IImageProcessor imageProcessor)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
ArgumentNullException.ThrowIfNull(path);
var filename = Path.GetFileNameWithoutExtension(path);

@ -5,9 +5,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Diacritics.Extensions;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;

@ -53,15 +53,9 @@ namespace Emby.Server.Implementations.Library
public void SaveUserData(User user, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken)
{
if (userData == null)
{
throw new ArgumentNullException(nameof(userData));
}
ArgumentNullException.ThrowIfNull(userData);
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
ArgumentNullException.ThrowIfNull(item);
cancellationToken.ThrowIfCancellationRequested();
@ -194,10 +188,7 @@ namespace Emby.Server.Implementations.Library
/// <exception cref="ArgumentNullException"><paramref name="data"/> is <c>null</c>.</exception>
private UserItemDataDto GetUserItemDataDto(UserItemData data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
ArgumentNullException.ThrowIfNull(data);
return new UserItemDataDto
{

@ -995,7 +995,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
throw new Exception("Tuner not found.");
throw new ResourceNotFoundException("Tuner not found.");
}
public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken)
@ -1223,10 +1223,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, ActiveRecordingInfo activeRecordingInfo)
{
if (timer == null)
{
throw new ArgumentNullException(nameof(timer));
}
ArgumentNullException.ThrowIfNull(timer);
LiveTvProgram programInfo = null;
@ -2347,10 +2344,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer)
{
if (seriesTimer == null)
{
throw new ArgumentNullException(nameof(seriesTimer));
}
ArgumentNullException.ThrowIfNull(seriesTimer);
var query = new InternalItemsQuery
{

@ -13,6 +13,7 @@ using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Extensions;
using Jellyfin.Extensions.Json;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@ -65,7 +66,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
await RecordFromFile(mediaSource, mediaSource.Path, targetFile, onStarted, cancellationTokenSource.Token).ConfigureAwait(false);
_logger.LogInformation("Recording completed to file {0}", targetFile);
_logger.LogInformation("Recording completed to file {Path}", targetFile);
}
private async Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, Action onStarted, CancellationToken cancellationToken)
@ -115,7 +116,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
_ = StartStreamingLog(_process.StandardError.BaseStream, _logFileStream);
_logger.LogInformation("ffmpeg recording process started for {0}", _targetPath);
_logger.LogInformation("ffmpeg recording process started for {Path}", _targetPath);
// Block until ffmpeg exits
await _taskCompletionSource.Task.ConfigureAwait(false);
}
private string GetCommandLineArgs(MediaSourceInfo mediaSource, string inputTempFile, string targetFile)
@ -294,7 +298,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
else
{
_taskCompletionSource.TrySetException(
new Exception(
new FfmpegException(
string.Format(
CultureInfo.InvariantCulture,
"Recording for {0} failed. Exit code {1}",

@ -84,10 +84,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public virtual void Update(T item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
ArgumentNullException.ThrowIfNull(item);
lock (_fileDataLock)
{
@ -107,10 +104,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public virtual void Add(T item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
ArgumentNullException.ThrowIfNull(item);
lock (_fileDataLock)
{

@ -2,6 +2,7 @@
using System;
using System.Globalization;
using System.Text;
using MediaBrowser.Controller.LiveTv;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
@ -48,12 +49,18 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (!string.IsNullOrWhiteSpace(info.EpisodeTitle))
{
var tmpName = name;
if (addHyphen)
{
name += " -";
tmpName += " -";
}
name += " " + info.EpisodeTitle;
tmpName += " " + info.EpisodeTitle;
// Since the filename will be used with file ext. (.mp4, .ts, etc)
if (Encoding.UTF8.GetByteCount(tmpName) < 250)
{
name = tmpName;
}
}
}
else if (info.IsMovie && info.ProductionYear != null)

@ -20,6 +20,7 @@ using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos;
using Jellyfin.Extensions;
using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@ -591,13 +592,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
catch (HttpRequestException ex)
{
if (ex.StatusCode.HasValue)
if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest)
{
if ((int)ex.StatusCode.Value == 400)
{
_tokens.Clear();
_lastErrorResponse = DateTime.UtcNow;
}
_tokens.Clear();
_lastErrorResponse = DateTime.UtcNow;
}
throw;
@ -662,7 +660,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return root.Token;
}
throw new Exception("Could not authenticate with Schedules Direct Error: " + root.Message);
throw new AuthenticationException("Could not authenticate with Schedules Direct Error: " + root.Message);
}
private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken)
@ -697,7 +695,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (string.IsNullOrEmpty(token))
{
throw new Exception("token required");
throw new ArgumentException("token required");
}
_logger.LogInformation("Headends on account ");
@ -768,14 +766,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var listingsId = info.ListingsId;
if (string.IsNullOrEmpty(listingsId))
{
throw new Exception("ListingsId required");
throw new ArgumentException("ListingsId required");
}
var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
if (string.IsNullOrEmpty(token))
{
throw new Exception("token required");
throw new ArgumentException("token required");
}
using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId);

@ -8,6 +8,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Extensions;
@ -26,6 +27,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
public class XmlTvListingsProvider : IListingsProvider
{
private static readonly TimeSpan _maxCacheAge = TimeSpan.FromHours(1);
private readonly IServerConfigurationManager _config;
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<XmlTvListingsProvider> _logger;
@ -69,13 +72,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return UnzipIfNeeded(info.Path, info.Path);
}
string cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + "-" + info.Id + ".xml";
string cacheFilename = info.Id + ".xml";
string cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename);
if (File.Exists(cacheFile))
if (File.Exists(cacheFile) && File.GetLastWriteTimeUtc(cacheFile) >= DateTime.UtcNow.Subtract(_maxCacheAge))
{
return UnzipIfNeeded(info.Path, cacheFile);
}
// Must check if file exists as parent directory may not exist.
if (File.Exists(cacheFile))
{
File.Delete(cacheFile);
}
_logger.LogInformation("Downloading xmltv listings from {Path}", info.Path);
Directory.CreateDirectory(Path.GetDirectoryName(cacheFile));
@ -124,7 +133,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
using (var stream = File.OpenRead(file))
{
string tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
string tempFolder = GetTempFolderPath(stream);
Directory.CreateDirectory(tempFolder);
_zipClient.ExtractFirstFileFromGz(stream, tempFolder, "data.xml");
@ -137,7 +146,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
using (var stream = File.OpenRead(file))
{
string tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
string tempFolder = GetTempFolderPath(stream);
Directory.CreateDirectory(tempFolder);
_zipClient.ExtractAllFromGz(stream, tempFolder, true);
@ -146,6 +155,16 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
}
private string GetTempFolderPath(Stream stream)
{
#pragma warning disable CA5351
using var md5 = MD5.Create();
#pragma warning restore CA5351
var checksum = Convert.ToHexString(md5.ComputeHash(stream));
stream.Position = 0;
return Path.Combine(_config.ApplicationPaths.TempDirectory, checksum);
}
private string FindXmlFile(string directory)
{
return _fileSystem.GetFiles(directory, true)

@ -196,7 +196,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
IsInfiniteStream = true,
IsRemote = isRemote,
IgnoreDts = true,
IgnoreDts = info.IgnoreDts,
SupportsDirectPlay = supportsDirectPlay,
SupportsDirectStream = supportsDirectStream,

@ -44,10 +44,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public async Task<Stream> GetListingsStream(TunerHostInfo info, CancellationToken cancellationToken)
{
if (info == null)
{
throw new ArgumentNullException(nameof(info));
}
ArgumentNullException.ThrowIfNull(info);
if (!info.Url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
@ -199,7 +196,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
if (string.IsNullOrWhiteSpace(numberString))
{
// Using this as a fallback now as this leads to Problems with channels like "5 USA"
// where 5 isn't ment to be the channel number
// where 5 isn't meant to be the channel number
// Check for channel number with the format from SatIp
// #EXTINF:0,84. VOX Schweiz
// #EXTINF:0,84.0 - VOX Schweiz

@ -119,5 +119,8 @@
"TaskCleanActivityLogDescription": "Verwyder aktiwiteitsaantekeninge ouer as die opgestelde ouderdom.",
"TaskCleanActivityLog": "Maak Aktiwiteitsaantekeninge Skoon",
"TaskOptimizeDatabaseDescription": "Komprimeer databasis en verkort vrye ruimte. As hierdie taak uitgevoer word nadat die media versameling geskandeer is of ander veranderings aangebring is wat databasisaanpassings impliseer, kan dit die prestasie verbeter.",
"TaskOptimizeDatabase": "Optimaliseer databasis"
"TaskOptimizeDatabase": "Optimaliseer databasis",
"TaskKeyframeExtractorDescription": "Haal keyframes vanuit video lêers om meer presiese HLS afspeellyste te maak. Dit kan lank duur.",
"TaskKeyframeExtractor": "Keyframe Ekstraktor",
"External": "Ekstern"
}

@ -1,9 +1,9 @@
{
"Albums": "ألبومات",
"Albums": "البومات",
"AppDeviceValues": "تطبيق: {0}, جهاز: {1}",
"Application": "تطبيق",
"Artists": "الفنانين",
"AuthenticationSucceededWithUserName": "{0} سجل الدخول بنجاح",
"AuthenticationSucceededWithUserName": "تمت مصادقة {0} بنجاح",
"Books": "الكتب",
"CameraImageUploadedFrom": "صورة كاميرا جديدة تم رفعها من {0}",
"Channels": "القنوات",
@ -14,7 +14,7 @@
"FailedLoginAttemptWithUserName": "محاولة تسجيل الدخول فشلت من {0}",
"Favorites": "مفضلات",
"Folders": "المجلدات",
"Genres": "التضنيفات",
"Genres": "التصنيفات",
"HeaderAlbumArtists": "فناني الألبوم",
"HeaderContinueWatching": "استمر بالمشاهدة",
"HeaderFavoriteAlbums": "الألبومات المفضلة",
@ -30,8 +30,8 @@
"ItemAddedWithName": "تم إضافة {0} للمكتبة",
"ItemRemovedWithName": "تم إزالة {0} من المكتبة",
"LabelIpAddressValue": "عنوان الآي بي: {0}",
"LabelRunningTimeValue": "المدة: {0}",
"Latest": "الأحدث",
"LabelRunningTimeValue": "مدة التشغيل: {0}",
"Latest": "أحدث",
"MessageApplicationUpdated": "لقد تم تحديث خادم Jellyfin",
"MessageApplicationUpdatedTo": "تم تحديث خادم Jellyfin الى {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "تم تحديث إعدادات الخادم في قسم {0}",
@ -40,7 +40,7 @@
"Movies": "الأفلام",
"Music": "الموسيقى",
"MusicVideos": "الفيديوهات الموسيقية",
"NameInstallFailed": "فشل التثبيت {0}",
"NameInstallFailed": "فشل تثبيت {0}",
"NameSeasonNumber": "الموسم {0}",
"NameSeasonUnknown": "الموسم غير معروف",
"NewVersionIsAvailable": "نسخة جديدة من خادم Jellyfin متوفرة للتحميل.",
@ -49,9 +49,9 @@
"NotificationOptionAudioPlayback": "بدأ تشغيل المقطع الصوتي",
"NotificationOptionAudioPlaybackStopped": "تم إيقاف تشغيل المقطع الصوتي",
"NotificationOptionCameraImageUploaded": "تم رفع صورة الكاميرا",
"NotificationOptionInstallationFailed": "فشل التثبيت",
"NotificationOptionInstallationFailed": "فشل في التثبيت",
"NotificationOptionNewLibraryContent": "تم إضافة محتوى جديد",
"NotificationOptionPluginError": "فشل في البرنامج المضاف",
"NotificationOptionPluginError": "فشل في الملحق",
"NotificationOptionPluginInstalled": "تم تثبيت الملحق",
"NotificationOptionPluginUninstalled": "تمت إزالة الملحق",
"NotificationOptionPluginUpdateInstalled": "تم تثبيت تحديثات الملحق",
@ -67,22 +67,22 @@
"PluginUninstalledWithName": "تمت إزالة {0}",
"PluginUpdatedWithName": "تم تحديث {0}",
"ProviderValue": "المزود: {0}",
"ScheduledTaskFailedWithName": "العملية {0} فشلت",
"ScheduledTaskStartedWithName": "تم بدء {0}",
"ServerNameNeedsToBeRestarted": "يحتاج لإعادة تشغيله {0}",
"Shows": "الحلقات",
"ScheduledTaskFailedWithName": "فشلت العملية {0}",
"ScheduledTaskStartedWithName": "تم بدء العملية {0}",
"ServerNameNeedsToBeRestarted": "يحتاج {0} لإعادة التشغيل",
"Shows": "العروض",
"Songs": "الأغاني",
"StartupEmbyServerIsLoading": "خادم Jellyfin قيد التشغيل . الرجاء المحاولة بعد قليل.",
"StartupEmbyServerIsLoading": "يتم تحميل خادم Jellyfin . الرجاء المحاولة بعد قليل.",
"SubtitleDownloadFailureForItem": "عملية إنزال الترجمة فشلت لـ{0}",
"SubtitleDownloadFailureFromForItem": "الترجمات فشلت في التحميل من {0} الى {1}",
"SubtitleDownloadFailureFromForItem": "فشل تحميل الترجمات من {0} ل {1}",
"Sync": "مزامنة",
"System": "النظام",
"TvShows": "البرامج التلفزيونية",
"User": "المستخدم",
"UserCreatedWithName": "تم إنشاء المستخدم {0}",
"UserDeletedWithName": "تم حذف المستخدم {0}",
"UserDownloadingItemWithValues": "{0} يقوم بإنزال {1}",
"UserLockedOutWithName": "المستخدم {0} تم منعه من الدخول",
"UserDownloadingItemWithValues": "يقوم {0} بتنزيل {1}",
"UserLockedOutWithName": "تم منع المستخدم {0} من الدخول",
"UserOfflineFromDevice": "تم قطع اتصال {0} من {1}",
"UserOnlineFromDevice": "{0} متصل عبر {1}",
"UserPasswordChangedWithName": "تم تغيير كلمة السر للمستخدم {0}",
@ -90,35 +90,38 @@
"UserStartedPlayingItemWithValues": "قام {0} ببدء تشغيل {1} على {2}",
"UserStoppedPlayingItemWithValues": "قام {0} بإيقاف تشغيل {1} على {2}",
"ValueHasBeenAddedToLibrary": "تمت اضافت {0} إلى مكتبة الوسائط",
"ValueSpecialEpisodeName": "خاص - {0}",
"ValueSpecialEpisodeName": "حلقه خاصه - {0}",
"VersionNumber": "النسخة {0}",
"TaskCleanCacheDescription": "يحذف ملفات ذاكرة التخزين المؤقت التي لم يعد النظام بحاجة إليها.",
"TaskCleanCache": "احذف مجلد ذاكرة التخزين المؤقت",
"TaskCleanCacheDescription": "يحذف الملفات المؤقتة التي لم يعد النظام بحاجة إليها.",
"TaskCleanCache": "احذف ما بمجلد الملفات المؤقتة",
"TasksChannelsCategory": "قنوات الإنترنت",
"TasksLibraryCategory": "مكتبة",
"TasksMaintenanceCategory": "صيانة",
"TaskRefreshLibraryDescription": قوم بفصح مكتبة الوسائط الخاصة بك بحثًا عن ملفات جديدة وتحديث البيانات الوصفية.",
"TaskRefreshLibraryDescription": فصح مكتبة الوسائط الخاصة بك بحثًا عن ملفات جديدة، ومن ثم يتحدث البيانات الوصفية.",
"TaskRefreshLibrary": "افحص مكتبة الوسائط",
"TaskRefreshChapterImagesDescription": "إنشاء صور مصغرة لمقاطع الفيديو ذات فصول.",
"TaskRefreshChapterImagesDescription": "يُنشئ صور مصغرة لمقاطع الفيديو التي تحتوي على فصول.",
"TaskRefreshChapterImages": "استخراج صور الفصل",
"TasksApplicationCategory": "تطبيق",
"TaskDownloadMissingSubtitlesDescription": "ابحث في الإنترنت على الترجمات المفقودة إستنادا على الميتاداتا.",
"TaskDownloadMissingSubtitles": "تحميل الترجمات المفقودة",
"TaskRefreshChannelsDescription": "تحديث معلومات قنوات الإنترنت.",
"TaskDownloadMissingSubtitlesDescription": "يبحث في الإنترنت على الترجمات الناقصة استنادا على البيانات الوصفية.",
"TaskDownloadMissingSubtitles": "تحميل الترجمات الناقصة",
"TaskRefreshChannelsDescription": "يحدث معلومات قنوات الإنترنت.",
"TaskRefreshChannels": "إعادة تحديث القنوات",
"TaskCleanTranscodeDescription": "حذف ملفات الترميز الأقدم من يوم واحد.",
"TaskCleanTranscode": "حذف سجلات الترميز",
"TaskCleanTranscodeDescription": "يحذف ملفات الترميز الأقدم من يوم واحد.",
"TaskCleanTranscode": "حذف ما بمجلد الترميز",
"TaskUpdatePluginsDescription": "تحميل وتثبيت الإضافات التي تم تفعيل التحديث التلقائي لها.",
"TaskUpdatePlugins": "تحديث الإضافات",
"TaskRefreshPeopleDescription": "تحديث البيانات الوصفية للممثلين والمخرجين في مكتبة الوسائط الخاصة بك.",
"TaskRefreshPeopleDescription": "يقوم بتحديث البيانات الوصفية للممثلين والمخرجين في مكتبة الوسائط الخاصة بك.",
"TaskRefreshPeople": "إعادة تحميل الأشخاص",
"TaskCleanLogsDescription": "حذف السجلات الأقدم من {0} يوم.",
"TaskCleanLogs": "حذف دليل السجل",
"TaskCleanActivityLogDescription": "يحذف سجل الأنشطة الأقدم من الوقت الموضوع.",
"TaskCleanLogsDescription": "يحذف السجلات الأقدم من {0} يوم.",
"TaskCleanLogs": "حذف مسار السجل",
"TaskCleanActivityLogDescription": "يحذف سجل الأنشطة الأقدم من الوقت الذي تم تحديده.",
"TaskCleanActivityLog": "حذف سجل الأنشطة",
"Default": "الإعدادات الافتراضية",
"Default": "افتراضي",
"Undefined": "غير معرف",
"Forced": "ملحقة",
"TaskOptimizeDatabaseDescription": "يضغط قاعدة البيانات ويقتطع المساحة الحرة. تشغيل هذه المهمة بعد فحص المكتبة أو إجراء تغييرات أخرى تشير ضمنًا إلى أن تعديلات قاعدة البيانات قد تؤدي إلى تحسين الأداء.",
"TaskOptimizeDatabase": "تحسين قاعدة البيانات"
"TaskOptimizeDatabaseDescription": "يضغط قاعدة البيانات ويقتطع المساحة الحرة. تشغيل هذه المهمة بعد فحص المكتبة أو إجراء تغييرات أخرى تتضمن تعديلات في قاعدة البيانات قد تؤدي إلى تحسين الأداء.",
"TaskOptimizeDatabase": "تحسين قاعدة البيانات",
"TaskKeyframeExtractorDescription": "يستخرج الإطارات الرئيسية من ملفات الفيديو لكي ينشئ قوائم تشغيل بث HTTP المباشر. قد تستمر هذه العملية لوقت طويل.",
"TaskKeyframeExtractor": "مستخرج الإطار الرئيسي",
"External": "خارجي"
}

@ -43,7 +43,7 @@
"NameInstallFailed": "{0} не можа да се инсталира",
"NameSeasonNumber": "Сезон {0}",
"NameSeasonUnknown": "Неразпознат сезон",
"NewVersionIsAvailable": "Нова версия на Jellyfin сървъра е достъпна за сваляне.",
"NewVersionIsAvailable": "Нова версия на Джелифин сървъра е достъпна за сваляне.",
"NotificationOptionApplicationUpdateAvailable": "Налично е обновление на програмата",
"NotificationOptionApplicationUpdateInstalled": "Обновлението на програмата е инсталирано",
"NotificationOptionAudioPlayback": "Възпроизвеждането на звук започна",
@ -120,5 +120,8 @@
"TaskCleanActivityLogDescription": "Изтрива записите в дневника с активност по стари от конфигурираната възраст.",
"TaskCleanActivityLog": "Изчисти дневника с активност",
"TaskOptimizeDatabaseDescription": "Прави базата данни по-компактна и освобождава място. Пускането на тази задача след сканиране на библиотеката или правене на други промени, свързани с модификации на базата данни, може да подобри производителността.",
"TaskOptimizeDatabase": "Оптимизирай базата данни"
"TaskOptimizeDatabase": "Оптимизирай базата данни",
"TaskKeyframeExtractorDescription": "Извличат се ключови кадри от видеофайловете ,за да се създаде по точен ХЛС списък . Задачата може да отнеме много време.",
"TaskKeyframeExtractor": "Извличане на ключови кадри",
"External": "Външен"
}

@ -20,7 +20,7 @@
"HeaderFavoriteAlbums": "Àlbums Preferits",
"HeaderFavoriteArtists": "Artistes Predilectes",
"HeaderFavoriteEpisodes": "Episodis Predilectes",
"HeaderFavoriteShows": "Programes Predilectes",
"HeaderFavoriteShows": "Sèries Predilectes",
"HeaderFavoriteSongs": "Cançons Predilectes",
"HeaderLiveTV": "TV en Directe",
"HeaderNextUp": "A continuació",
@ -70,7 +70,7 @@
"ScheduledTaskFailedWithName": "{0} ha fallat",
"ScheduledTaskStartedWithName": "{0} iniciat",
"ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciat",
"Shows": "Programes",
"Shows": "Sèries",
"Songs": "Cançons",
"StartupEmbyServerIsLoading": "El Servidor d'Jellyfin est&agrave; carregant. Si et plau, prova de nou en breus.",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",

@ -121,7 +121,7 @@
"Default": "Standard",
"TaskOptimizeDatabaseDescription": "Komprimiert die Datenbank und trimmt den freien Speicherplatz. Die Ausführung dieser Aufgabe nach dem Scannen der Bibliothek oder nach anderen Änderungen, die Datenbankänderungen implizieren, kann die Leistung verbessern.",
"TaskOptimizeDatabase": "Datenbank optimieren",
"TaskKeyframeExtractorDescription": "Extrahiere Keyframes aus Videodateien, um präzisere HLS-Playlisten zu erzeugen. Diese Aufgabe kann sehr lange dauern.",
"TaskKeyframeExtractorDescription": "Extrahiere Keyframes aus Videodateien, um präzisere HLS-Playlisten zu erzeugen. Dieser Vorgang kann sehr lange dauern.",
"TaskKeyframeExtractor": "Keyframe Extraktor",
"External": "Extern"
}

@ -5,17 +5,17 @@
"Artists": "Καλλιτέχνες",
"AuthenticationSucceededWithUserName": "Ο χρήστης {0} επαληθεύτηκε επιτυχώς",
"Books": "Βιβλία",
"CameraImageUploadedFrom": "Μια νέα εικόνα κάμερας έχει αποσταλεί από {0}",
"CameraImageUploadedFrom": "Μια νέα φωτογραφία φορτώθηκε από {0}",
"Channels": "Κανάλια",
"ChapterNameValue": "Κεφάλαιο {0}",
"Collections": "Συλλογές",
"DeviceOfflineWithName": "{0} αποσυνδέθηκε",
"DeviceOnlineWithName": "{0} συνδέθηκε",
"DeviceOfflineWithName": "Ο/Η {0} αποσυνδέθηκε",
"DeviceOnlineWithName": "Ο/Η {0} συνδέθηκε",
"FailedLoginAttemptWithUserName": "Αποτυχημένη προσπάθεια σύνδεσης από {0}",
"Favorites": "Αγαπημένα",
"Folders": "Φάκελοι",
"Genres": "Είδη",
"HeaderAlbumArtists": "Καλλιτέχνες άλμπουμ",
"HeaderAlbumArtists": "Δισκογραφικοί καλλιτέχνες",
"HeaderContinueWatching": "Συνεχίστε την παρακολούθηση",
"HeaderFavoriteAlbums": "Αγαπημένα Άλμπουμ",
"HeaderFavoriteArtists": "Αγαπημένοι Καλλιτέχνες",
@ -24,7 +24,7 @@
"HeaderFavoriteSongs": "Αγαπημένα Τραγούδια",
"HeaderLiveTV": "Ζωντανή Τηλεόραση",
"HeaderNextUp": "Επόμενο",
"HeaderRecordingGroups": "Γκρουπ Εγγραφών",
"HeaderRecordingGroups": "Μουσικά Συγκροτήματα",
"HomeVideos": "Προσωπικά βίντεο",
"Inherit": "Κληρονόμηση",
"ItemAddedWithName": "{0} προστέθηκε στη βιβλιοθήκη",
@ -32,10 +32,10 @@
"LabelIpAddressValue": "Διεύθυνση IP: {0}",
"LabelRunningTimeValue": "Διάρκεια: {0}",
"Latest": "Πρόσφατα",
"MessageApplicationUpdated": "Ο Jellyfin Server έχει ενημερωθεί",
"MessageApplicationUpdatedTo": "Ο server Jellyfin αναβαθμίστηκε σε έκδοση {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "Η ενότητα {0} ρύθμισης παραμέτρων του server έχει ενημερωθεί",
"MessageServerConfigurationUpdated": "Η ρύθμιση παραμέτρων του server έχει ενημερωθεί",
"MessageApplicationUpdated": "Ο διακομιστής Jellyfin έχει ενημερωθεί",
"MessageApplicationUpdatedTo": "Ο διακομιστής Jellyfin αναβαθμίστηκε στην έκδοση {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "Η ενότητα {0} ρύθμισης παραμέτρων του διακομιστή έχει ενημερωθεί",
"MessageServerConfigurationUpdated": "Η ρύθμιση παραμέτρων του διακομιστή έχει ενημερωθεί",
"MixedContent": "Ανάμεικτο Περιεχόμενο",
"Movies": "Ταινίες",
"Music": "Μουσική",
@ -43,7 +43,7 @@
"NameInstallFailed": "{0} η εγκατάσταση απέτυχε",
"NameSeasonNumber": "Κύκλος {0}",
"NameSeasonUnknown": "Άγνωστος Κύκλος",
"NewVersionIsAvailable": "Μια νέα έκδοση του Jellyfin Server είναι διαθέσιμη για λήψη.",
"NewVersionIsAvailable": "Μια νέα έκδοση του διακομιστή Jellyfin είναι διαθέσιμη για λήψη.",
"NotificationOptionApplicationUpdateAvailable": "Διαθέσιμη ενημερωμένη έκδοση εφαρμογής",
"NotificationOptionApplicationUpdateInstalled": "Η ενημέρωση εφαρμογής εγκαταστάθηκε",
"NotificationOptionAudioPlayback": "Η αναπαραγωγή ήχου ξεκίνησε",
@ -55,7 +55,7 @@
"NotificationOptionPluginInstalled": "Το plugin εγκαταστάθηκε",
"NotificationOptionPluginUninstalled": "Το plugin απεγκαταστάθηκε",
"NotificationOptionPluginUpdateInstalled": "Η αναβάθμιση του plugin εγκαταστάθηκε",
"NotificationOptionServerRestartRequired": "Απαιτείται επανεκκίνηση του server",
"NotificationOptionServerRestartRequired": "Ο διακομιστής χρειάζεται επανεκκίνηση",
"NotificationOptionTaskFailed": "Αποτυχία προγραμματισμένης εργασίας",
"NotificationOptionUserLockedOut": "Ο χρήστης αποκλείστηκε",
"NotificationOptionVideoPlayback": "Η αναπαραγωγή βίντεο ξεκίνησε",
@ -72,7 +72,7 @@
"ServerNameNeedsToBeRestarted": "{0} χρειάζεται επανεκκίνηση",
"Shows": "Σειρές",
"Songs": "Τραγούδια",
"StartupEmbyServerIsLoading": "Ο Jellyfin Server φορτώνει. Παρακαλώ δοκιμάστε σε λίγο.",
"StartupEmbyServerIsLoading": "Ο διακομιστής Jellyfin φορτώνει. Περιμένετε λίγο και δοκιμάστε ξανά.",
"SubtitleDownloadFailureForItem": "Οι υπότιτλοι απέτυχαν να κατέβουν για {0}",
"SubtitleDownloadFailureFromForItem": "Αποτυχίες μεταφόρτωσης υποτίτλων από {0} για {1}",
"Sync": "Συγχρονισμός",
@ -121,7 +121,7 @@
"Default": "Προεπιλογή",
"TaskOptimizeDatabaseDescription": "Συμπιέζει τη βάση δεδομένων και δημιουργεί ελεύθερο χώρο. Η εκτέλεση αυτής της εργασίας μετά τη σάρωση της βιβλιοθήκης ή την πραγματοποίηση άλλων αλλαγών που συνεπάγονται τροποποιήσεις της βάσης δεδομένων μπορεί να βελτιώσει την απόδοση.",
"TaskOptimizeDatabase": "Βελτιστοποίηση βάσης δεδομένων",
"TaskKeyframeExtractorDescription": "Εξάγει τα βασικά καρέ από αρχεία βίντεο για να δημιουργήσει πιο ακριβείς HLS λίστες αναπαραγωγής. Αυτή η εργασία μπορεί να διαρκέσει πολλή ώρα.",
"TaskKeyframeExtractorDescription": "Εξάγει καρέ από αρχεία βίντεο για να δημιουργήσει πιο ακριβείς λίστες αναπαραγωγής HLS. Αυτή η διεργασία μπορεί να πάρει χρόνο.",
"TaskKeyframeExtractor": "Εξαγωγέας βασικών καρέ βίντεο",
"External": "Εξωτερικό"
}

@ -121,5 +121,7 @@
"Default": "Por Defecto",
"TaskOptimizeDatabaseDescription": "Compacta la base de datos y restaura el espacio libre. Ejecutar esta tarea después de actualizar las librerías o realizar otros cambios que impliquen modificar las bases de datos puede mejorar la performance.",
"TaskOptimizeDatabase": "Optimización de base de datos",
"External": "Externo"
"External": "Externo",
"TaskKeyframeExtractorDescription": "Extrae Fotogramas Clave de los archivos de vídeo para crear Listas de Reprodución HLS más precisas. Esta tarea puede durar mucho tiempo.",
"TaskKeyframeExtractor": "Extractor de Fotogramas Clave"
}

@ -122,5 +122,6 @@
"TaskOptimizeDatabase": "Optimizar base de datos",
"TaskOptimizeDatabaseDescription": "Compacta la base de datos y trunca el espacio libre. Puede mejorar el rendimiento si se realiza esta tarea después de escanear la biblioteca o después de realizar otros cambios que impliquen modificar la base de datos.",
"TaskKeyframeExtractorDescription": "Extrae los cuadros clave de los archivos de vídeo para crear listas HLS más precisas. Esta tarea puede tardar un buen rato.",
"TaskKeyframeExtractor": "Extractor de Cuadros Clave"
"TaskKeyframeExtractor": "Extractor de Cuadros Clave",
"External": "Externo"
}

@ -74,7 +74,7 @@
"Songs": "Canciones",
"StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
"SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}",
"SubtitleDownloadFailureFromForItem": "Fallo de descarga de subtítulos desde {0} para {1}",
"SubtitleDownloadFailureFromForItem": "Fallo en la descarga de subtítulos desde {0} para {1}",
"Sync": "Sincronizar",
"System": "Sistema",
"TvShows": "Series",
@ -93,19 +93,19 @@
"ValueSpecialEpisodeName": "Especial - {0}",
"VersionNumber": "Versión {0}",
"TasksMaintenanceCategory": "Mantenimiento",
"TasksLibraryCategory": "Librería",
"TasksLibraryCategory": "Biblioteca",
"TasksApplicationCategory": "Aplicación",
"TasksChannelsCategory": "Canales de internet",
"TaskCleanCache": "Eliminar archivos temporales",
"TaskCleanCacheDescription": "Elimina los archivos temporales que ya no son necesarios para el servidor.",
"TaskRefreshChapterImages": "Extraer imágenes de los capítulos",
"TaskRefreshChapterImagesDescription": "Crea las miniaturas de los vídeos que tengan capítulos.",
"TaskRefreshChapterImagesDescription": "Crear miniaturas de los vídeos que tengan capítulos.",
"TaskRefreshLibrary": "Escanear la biblioteca",
"TaskRefreshLibraryDescription": "Añade los archivos que se hayan añadido a la biblioteca y actualiza las etiquetas de los ya presentes.",
"TaskCleanLogs": "Limpiar registros",
"TaskCleanLogsDescription": "Elimina los archivos de registro que tengan más de {0} días.",
"TaskRefreshPeople": "Actualizar personas",
"TaskRefreshPeopleDescription": "Actualiza las etiquetas de los intérpretes y directores presentes en tus bibliotecas.",
"TaskRefreshPeopleDescription": "Actualiza las etiquetas de los actores y directores presentes en tus bibliotecas.",
"TaskUpdatePlugins": "Actualizar extensiones",
"TaskUpdatePluginsDescription": "Actualiza las extensiones que están configuradas para actualizarse automáticamente.",
"TaskCleanTranscode": "Limpiar las transcodificaciones",
@ -120,7 +120,7 @@
"Forced": "Forzado",
"Default": "Predeterminado",
"TaskOptimizeDatabase": "Optimizar la base de datos",
"TaskOptimizeDatabaseDescription": "Compacta y libera el espacio libre en la base de datos. Ejecutar esta tarea tras escanear la biblioteca o hacer cambios que impliquen modificaciones en la base de datos puede mejorar el rendimiento.",
"TaskOptimizeDatabaseDescription": "Optimiza y libera el espacio libre en la base de datos. Ejecutar esta tarea tras escanear la biblioteca o hacer cambios que impliquen modificaciones en la base de datos puede mejorar el rendimiento.",
"TaskKeyframeExtractorDescription": "Extrae los fotogramas clave de los archivos de vídeo para crear listas HLS más precisas. Esta tarea puede tardar mucho tiempo.",
"TaskKeyframeExtractor": "Extractor de Fotogramas Clave",
"External": "Externo"

@ -119,5 +119,8 @@
"Forced": "Forzado",
"Default": "Por defecto",
"TaskOptimizeDatabaseDescription": "Compacta la base de datos y libera espacio. Ejecutar esta tarea después de escanear la biblioteca o hacer otros cambios que impliquen modificaciones en la base de datos puede mejorar el rendimiento.",
"TaskOptimizeDatabase": "Optimizar base de datos"
"TaskOptimizeDatabase": "Optimizar base de datos",
"External": "Externo",
"TaskKeyframeExtractorDescription": "Extrae Fotogramas Clave de los archivos de vídeo para crear Listas de Reproducción HLS más precisas. Esta tarea puede durar mucho tiempo.",
"TaskKeyframeExtractor": "Extractor de Fotogramas Clave"
}

@ -19,5 +19,7 @@
"FailedLoginAttemptWithUserName": "Intento de inicio de sesión fallido de {0}",
"HeaderFavoriteSongs": "Canciones Favoritas",
"HeaderFavoriteEpisodes": "Episodios Favoritos",
"HeaderFavoriteArtists": "Artistas Favoritos"
"HeaderFavoriteArtists": "Artistas Favoritos",
"External": "Externo",
"Default": "Predeterminado"
}

@ -119,5 +119,6 @@
"SubtitleDownloadFailureFromForItem": "Subtiitrite allalaadimine {0} > {1} nurjus",
"UserPolicyUpdatedWithName": "Kasutaja {0} õigusi värskendati",
"UserStoppedPlayingItemWithValues": "{0} lõpetas {1} taasesituse seadmes {2}",
"UserOnlineFromDevice": "{0} on ühendatud seadmest {1}"
"UserOnlineFromDevice": "{0} on ühendatud seadmest {1}",
"External": "Väline"
}

@ -1,5 +1,5 @@
{
"HeaderLiveTV": "Suora TV",
"HeaderLiveTV": "Televisio",
"NewVersionIsAvailable": "Uusi versio Jellyfin-palvelimesta on ladattavissa.",
"NameSeasonUnknown": "Tuntematon kausi",
"NameSeasonNumber": "Kausi {0}",

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

Loading…
Cancel
Save