Merge branch 'jellyfin:master' into gzip

This commit is contained in:
adrez99 2022-10-11 18:15:28 +02:00 committed by GitHub
commit 177f53444d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
355 changed files with 3039 additions and 8169 deletions

View File

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

View File

@ -22,7 +22,7 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Setup .NET Core - name: Setup .NET Core
uses: actions/setup-dotnet@v2 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: '6.0.x' dotnet-version: '6.0.x'

View File

@ -17,7 +17,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }} repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Setup .NET Core - name: Setup .NET Core
uses: actions/setup-dotnet@v2 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: '6.0.x' dotnet-version: '6.0.x'
- name: Generate openapi.json - name: Generate openapi.json
@ -41,7 +41,7 @@ jobs:
with: with:
ref: ${{ github.base_ref }} ref: ${{ github.base_ref }}
- name: Setup .NET Core - name: Setup .NET Core
uses: actions/setup-dotnet@v2 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: '6.0.x' dotnet-version: '6.0.x'
- name: Generate openapi.json - name: Generate openapi.json

View File

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

View File

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

View File

@ -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. # mesa-va-drivers: needed for AMD VAAPI. Mesa >= 20.1 is required for HEVC transcoding.
# curl: healthcheck # curl: healthcheck
RUN apt-get update \ 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 - \ && 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 \ && 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 \ && apt-get update \
@ -53,7 +53,7 @@ RUN apt-get update \
&& dpkg -i *.deb \ && dpkg -i *.deb \
&& cd .. \ && cd .. \
&& rm -rf intel-compute-runtime \ && 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 clean autoclean -y \
&& apt-get autoremove -y \ && apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/apt/lists/* \
@ -72,7 +72,7 @@ COPY . .
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment # 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 # 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 FROM app

View File

@ -38,9 +38,6 @@ RUN apt-get update \
libssl-dev \ libssl-dev \
libfontconfig1 \ libfontconfig1 \
libfreetype6 \ libfreetype6 \
libomxil-bellagio0 \
libomxil-bellagio-bin \
libraspberrypi0 \
vainfo \ vainfo \
libva2 \ libva2 \
locales \ locales \
@ -64,7 +61,7 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# Discard objs - may cause failures if exists # Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r RUN find . -type d -name obj | xargs -r rm -r
# Build # 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 FROM app

View File

@ -55,7 +55,7 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# Discard objs - may cause failures if exists # Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r RUN find . -type d -name obj | xargs -r rm -r
# Build # 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 FROM app

View File

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

View File

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

View File

@ -446,7 +446,7 @@ namespace Emby.Dlna.Didl
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// If context is a season, this will return a string containing just episode number and name. /// 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> /// </remarks>
/// <param name="episode">The episode.</param> /// <param name="episode">The episode.</param>
/// <param name="context">Current context.</param> /// <param name="context">Current context.</param>

View File

@ -1,4 +1,5 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@ -61,6 +62,7 @@ namespace Emby.Dlna
try try
{ {
await ExtractSystemProfilesAsync().ConfigureAwait(false); await ExtractSystemProfilesAsync().ConfigureAwait(false);
Directory.CreateDirectory(UserProfilesPath);
LoadProfiles(); LoadProfiles();
} }
catch (Exception ex) catch (Exception ex)
@ -100,10 +102,7 @@ namespace Emby.Dlna
/// <inheritdoc /> /// <inheritdoc />
public DeviceProfile? GetProfile(DeviceIdentification deviceInfo) public DeviceProfile? GetProfile(DeviceIdentification deviceInfo)
{ {
if (deviceInfo == null) ArgumentNullException.ThrowIfNull(deviceInfo);
{
throw new ArgumentNullException(nameof(deviceInfo));
}
var profile = GetProfiles() var profile = GetProfiles()
.FirstOrDefault(i => i.Identification != null && IsMatch(deviceInfo, i.Identification)); .FirstOrDefault(i => i.Identification != null && IsMatch(deviceInfo, i.Identification));
@ -123,7 +122,7 @@ namespace Emby.Dlna
/// <summary> /// <summary>
/// Attempts to match a device with a profile. /// Attempts to match a device with a profile.
/// Rules: /// 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. /// - the profile field can be an exact match, or a reg exp.
/// </summary> /// </summary>
/// <param name="deviceInfo">The <see cref="DeviceIdentification"/> of the device.</param> /// <param name="deviceInfo">The <see cref="DeviceIdentification"/> of the device.</param>
@ -170,10 +169,7 @@ namespace Emby.Dlna
/// <inheritdoc /> /// <inheritdoc />
public DeviceProfile? GetProfile(IHeaderDictionary headers) public DeviceProfile? GetProfile(IHeaderDictionary headers)
{ {
if (headers == null) ArgumentNullException.ThrowIfNull(headers);
{
throw new ArgumentNullException(nameof(headers));
}
var profile = GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification)); var profile = GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification));
if (profile == null) if (profile == null)
@ -328,32 +324,28 @@ namespace Emby.Dlna
var path = Path.Join( var path = Path.Join(
systemProfilesPath, 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 // The stream should exist as we just got its name from GetManifestResourceNames
using (var stream = _assembly.GetManifestResourceStream(name)!) using (var stream = _assembly.GetManifestResourceStream(name)!)
{ {
var length = stream.Length; Directory.CreateDirectory(systemProfilesPath);
var fileInfo = _fileSystem.GetFileInfo(path);
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); await stream.CopyToAsync(fileStream).ConfigureAwait(false);
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);
}
} }
} }
} }
// Not necessary, but just to make it easy to find
Directory.CreateDirectory(UserProfilesPath);
} }
/// <inheritdoc /> /// <inheritdoc />
@ -406,14 +398,20 @@ namespace Emby.Dlna
} }
var current = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, profileId, StringComparison.OrdinalIgnoreCase)); 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 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) && if (!string.Equals(path, current.Path, StringComparison.Ordinal))
current.Info.Type != DeviceProfileType.System)
{ {
_fileSystem.DeleteFile(current.Path); lock (_profiles)
{
_profiles.Remove(current.Path);
}
} }
SaveProfile(profile, path, DeviceProfileType.User); SaveProfile(profile, path, DeviceProfileType.User);
@ -496,72 +494,4 @@ namespace Emby.Dlna
internal string Path { get; } 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()
{
}
}*/
} }

View File

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

View File

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

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

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

View File

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

View File

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

View File

@ -2,7 +2,6 @@
using System; using System;
using System.Globalization; using System.Globalization;
using System.Linq;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles 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();
}
} }
} }

View File

@ -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>();
}
}
}

View File

@ -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>();
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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>();
}
}
}

View File

@ -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"
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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>();
}
}
}

View File

@ -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>();
}
}
}

View File

@ -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"
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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"
}
};
}
}
}

View File

@ -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

View File

@ -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
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

@ -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
}
};
}
}
}

View File

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

View File

@ -153,7 +153,7 @@ namespace Emby.Naming.Common
CleanStrings = new[] CleanStrings = new[]
{ {
@"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r3|r5|bd5|bd|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|blu-ray|x264|x265|h264|h265|xvid|xvidvd|xxx|www.www|AAC|DTS|\[.*\])([ _\,\.\(\)\[\]\-]|$)", @"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r5|bd5|bd|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|blu-ray|x264|x265|h264|h265|xvid|xvidvd|xxx|www.www|AAC|DTS|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
@"^(?<cleaned>.+?)(\[.*\])", @"^(?<cleaned>.+?)(\[.*\])",
@"^\s*(?<cleaned>.+?)\WE[0-9]+(-|~)E?[0-9]+(\W|$)", @"^\s*(?<cleaned>.+?)\WE[0-9]+(-|~)E?[0-9]+(\W|$)",
@"^\s*\[[^\]]+\](?!\.\w+$)\s*(?<cleaned>.+)", @"^\s*\[[^\]]+\](?!\.\w+$)\s*(?<cleaned>.+)",
@ -181,6 +181,24 @@ namespace Emby.Naming.Common
"volume" "volume"
}; };
ArtistSubfolders = new[]
{
"albums",
"broadcasts",
"bootlegs",
"compilations",
"dj-mixes",
"eps",
"live",
"mixtapes",
"others",
"remixes",
"singles",
"soundtracks",
"spokenwords",
"streets"
};
AudioFileExtensions = new[] AudioFileExtensions = new[]
{ {
".669", ".669",
@ -280,6 +298,13 @@ namespace Emby.Naming.Common
"default" "default"
}; };
MediaHearingImpairedFlags = new[]
{
"cc",
"hi",
"sdh"
};
EpisodeExpressions = new[] EpisodeExpressions = new[]
{ {
// *** Begin Kodi Standard Naming // *** Begin Kodi Standard Naming
@ -504,6 +529,12 @@ namespace Emby.Naming.Common
"extras", "extras",
MediaType.Video), MediaType.Video),
new ExtraRule(
ExtraType.Unknown,
ExtraRuleType.DirectoryName,
"other",
MediaType.Video),
new ExtraRule( new ExtraRule(
ExtraType.Trailer, ExtraType.Trailer,
ExtraRuleType.Filename, ExtraRuleType.Filename,
@ -622,6 +653,12 @@ namespace Emby.Naming.Common
ExtraType.Unknown, ExtraType.Unknown,
ExtraRuleType.Suffix, ExtraRuleType.Suffix,
"-extra", "-extra",
MediaType.Video),
new ExtraRule(
ExtraType.Unknown,
ExtraRuleType.Suffix,
"-other",
MediaType.Video) MediaType.Video)
}; };
@ -727,11 +764,21 @@ namespace Emby.Naming.Common
/// </summary> /// </summary>
public string[] MediaDefaultFlags { get; set; } public string[] MediaDefaultFlags { get; set; }
/// <summary>
/// Gets or sets list of external media hearing impaired flags.
/// </summary>
public string[] MediaHearingImpairedFlags { get; set; }
/// <summary> /// <summary>
/// Gets or sets list of album stacking prefixes. /// Gets or sets list of album stacking prefixes.
/// </summary> /// </summary>
public string[] AlbumStackingPrefixes { get; set; } public string[] AlbumStackingPrefixes { get; set; }
/// <summary>
/// Gets or sets list of artist subfolders.
/// </summary>
public string[] ArtistSubfolders { get; set; }
/// <summary> /// <summary>
/// Gets or sets list of subtitle file extensions. /// Gets or sets list of subtitle file extensions.
/// </summary> /// </summary>

View File

@ -99,6 +99,18 @@ namespace Emby.Naming.ExternalFiles
pathInfo.Language = culture.ThreeLetterISOLanguageName; pathInfo.Language = culture.ThreeLetterISOLanguageName;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase); extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
} }
else if (culture != null && pathInfo.Language == "hin")
{
// Hindi language code "hi" collides with a hearing impaired flag - use as Hindi only if no other language is set
pathInfo.IsHearingImpaired = true;
pathInfo.Language = culture.ThreeLetterISOLanguageName;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
}
else if (_namingOptions.MediaHearingImpairedFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
{
pathInfo.IsHearingImpaired = true;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
}
else else
{ {
titleString = currentSlice + titleString; titleString = currentSlice + titleString;

View File

@ -11,11 +11,13 @@ namespace Emby.Naming.ExternalFiles
/// <param name="path">Path to file.</param> /// <param name="path">Path to file.</param>
/// <param name="isDefault">Is default.</param> /// <param name="isDefault">Is default.</param>
/// <param name="isForced">Is forced.</param> /// <param name="isForced">Is forced.</param>
public ExternalPathParserResult(string path, bool isDefault = false, bool isForced = false) /// <param name="isHearingImpaired">For the hearing impaired.</param>
public ExternalPathParserResult(string path, bool isDefault = false, bool isForced = false, bool isHearingImpaired = false)
{ {
Path = path; Path = path;
IsDefault = isDefault; IsDefault = isDefault;
IsForced = isForced; IsForced = isForced;
IsHearingImpaired = isHearingImpaired;
} }
/// <summary> /// <summary>
@ -47,5 +49,11 @@ namespace Emby.Naming.ExternalFiles
/// </summary> /// </summary>
/// <value><c>true</c> if this instance is forced; otherwise, <c>false</c>.</value> /// <value><c>true</c> if this instance is forced; otherwise, <c>false</c>.</value>
public bool IsForced { get; set; } public bool IsForced { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is for the hearing impaired.
/// </summary>
/// <value><c>true</c> if this instance is for the hearing impaired; otherwise, <c>false</c>.</value>
public bool IsHearingImpaired { get; set; }
} }
} }

View File

@ -15,7 +15,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="TagLibSharp" Version="2.2.0" /> <PackageReference Include="TagLibSharp" Version="2.3.0" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>

View File

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

View File

@ -66,6 +66,7 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Lyrics;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Notifications; using MediaBrowser.Controller.Notifications;
@ -93,6 +94,7 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System; using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Tasks;
using MediaBrowser.Providers.Chapters; using MediaBrowser.Providers.Chapters;
using MediaBrowser.Providers.Lyric;
using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.Plugins.Tmdb; using MediaBrowser.Providers.Plugins.Tmdb;
using MediaBrowser.Providers.Subtitles; using MediaBrowser.Providers.Subtitles;
@ -595,6 +597,7 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>(); serviceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>();
serviceCollection.AddSingleton<ISubtitleManager, SubtitleManager>(); serviceCollection.AddSingleton<ISubtitleManager, SubtitleManager>();
serviceCollection.AddSingleton<ILyricManager, LyricManager>();
serviceCollection.AddSingleton<IProviderManager, ProviderManager>(); serviceCollection.AddSingleton<IProviderManager, ProviderManager>();
@ -627,8 +630,6 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>(); serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
serviceCollection.AddScoped<ISessionContext, SessionContext>();
serviceCollection.AddSingleton<IAuthService, AuthService>(); serviceCollection.AddSingleton<IAuthService, AuthService>();
serviceCollection.AddSingleton<IQuickConnect, QuickConnectManager>(); serviceCollection.AddSingleton<IQuickConnect, QuickConnectManager>();

View File

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

View File

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

View File

@ -178,7 +178,8 @@ namespace Emby.Server.Implementations.Data
"RpuPresentFlag", "RpuPresentFlag",
"ElPresentFlag", "ElPresentFlag",
"BlPresentFlag", "BlPresentFlag",
"DvBlSignalCompatibilityId" "DvBlSignalCompatibilityId",
"IsHearingImpaired"
}; };
private static readonly string _mediaStreamSaveColumnsInsertQuery = private static readonly string _mediaStreamSaveColumnsInsertQuery =
@ -349,7 +350,8 @@ namespace Emby.Server.Implementations.Data
public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager) public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager)
{ {
const string CreateMediaStreamsTableCommand 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, 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))"; = "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, IsHearingImpaired BIT NULL, PRIMARY KEY (ItemId, StreamIndex))";
const string CreateMediaAttachmentsTableCommand 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))"; = "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))";
@ -572,6 +574,8 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "MediaStreams", "ElPresentFlag", "INT", existingColumnNames); AddColumn(db, "MediaStreams", "ElPresentFlag", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "BlPresentFlag", "INT", existingColumnNames); AddColumn(db, "MediaStreams", "BlPresentFlag", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "DvBlSignalCompatibilityId", "INT", existingColumnNames); AddColumn(db, "MediaStreams", "DvBlSignalCompatibilityId", "INT", existingColumnNames);
AddColumn(db, "MediaStreams", "IsHearingImpaired", "BIT", existingColumnNames);
}, },
TransactionMode); TransactionMode);
@ -583,10 +587,7 @@ namespace Emby.Server.Implementations.Data
public void SaveImages(BaseItem item) public void SaveImages(BaseItem item)
{ {
if (item == null) ArgumentNullException.ThrowIfNull(item);
{
throw new ArgumentNullException(nameof(item));
}
CheckDisposed(); CheckDisposed();
@ -617,10 +618,7 @@ namespace Emby.Server.Implementations.Data
/// </exception> /// </exception>
public void SaveItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken) public void SaveItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
{ {
if (items == null) ArgumentNullException.ThrowIfNull(items);
{
throw new ArgumentNullException(nameof(items));
}
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@ -2085,10 +2083,7 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException(nameof(id)); throw new ArgumentNullException(nameof(id));
} }
if (chapters == null) ArgumentNullException.ThrowIfNull(chapters);
{
throw new ArgumentNullException(nameof(chapters));
}
var idBlob = id.ToByteArray(); var idBlob = id.ToByteArray();
@ -2557,10 +2552,7 @@ namespace Emby.Server.Implementations.Data
public int GetCount(InternalItemsQuery query) public int GetCount(InternalItemsQuery query)
{ {
if (query == null) ArgumentNullException.ThrowIfNull(query);
{
throw new ArgumentNullException(nameof(query));
}
CheckDisposed(); CheckDisposed();
@ -2613,10 +2605,7 @@ namespace Emby.Server.Implementations.Data
public List<BaseItem> GetItemList(InternalItemsQuery query) public List<BaseItem> GetItemList(InternalItemsQuery query)
{ {
if (query == null) ArgumentNullException.ThrowIfNull(query);
{
throw new ArgumentNullException(nameof(query));
}
CheckDisposed(); CheckDisposed();
@ -2794,10 +2783,7 @@ namespace Emby.Server.Implementations.Data
public QueryResult<BaseItem> GetItems(InternalItemsQuery query) public QueryResult<BaseItem> GetItems(InternalItemsQuery query)
{ {
if (query == null) ArgumentNullException.ThrowIfNull(query);
{
throw new ArgumentNullException(nameof(query));
}
CheckDisposed(); CheckDisposed();
@ -3174,10 +3160,7 @@ namespace Emby.Server.Implementations.Data
public List<Guid> GetItemIdsList(InternalItemsQuery query) public List<Guid> GetItemIdsList(InternalItemsQuery query)
{ {
if (query == null) ArgumentNullException.ThrowIfNull(query);
{
throw new ArgumentNullException(nameof(query));
}
CheckDisposed(); CheckDisposed();
@ -4837,10 +4820,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
public List<string> GetPeopleNames(InternalPeopleQuery query) public List<string> GetPeopleNames(InternalPeopleQuery query)
{ {
if (query == null) ArgumentNullException.ThrowIfNull(query);
{
throw new ArgumentNullException(nameof(query));
}
CheckDisposed(); CheckDisposed();
@ -4880,10 +4860,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
public List<PersonInfo> GetPeople(InternalPeopleQuery query) public List<PersonInfo> GetPeople(InternalPeopleQuery query)
{ {
if (query == null) ArgumentNullException.ThrowIfNull(query);
{
throw new ArgumentNullException(nameof(query));
}
CheckDisposed(); CheckDisposed();
@ -4999,10 +4976,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentNullException(nameof(itemId)); throw new ArgumentNullException(nameof(itemId));
} }
if (ancestorIds == null) ArgumentNullException.ThrowIfNull(ancestorIds);
{
throw new ArgumentNullException(nameof(ancestorIds));
}
CheckDisposed(); CheckDisposed();
@ -5175,10 +5149,7 @@ AND Type = @InternalPersonType)");
private QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetItemValues(InternalItemsQuery query, int[] itemValueTypes, string returnType) private QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetItemValues(InternalItemsQuery query, int[] itemValueTypes, string returnType)
{ {
if (query == null) ArgumentNullException.ThrowIfNull(query);
{
throw new ArgumentNullException(nameof(query));
}
if (!query.Limit.HasValue) if (!query.Limit.HasValue)
{ {
@ -5531,10 +5502,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentNullException(nameof(itemId)); throw new ArgumentNullException(nameof(itemId));
} }
if (values == null) ArgumentNullException.ThrowIfNull(values);
{
throw new ArgumentNullException(nameof(values));
}
CheckDisposed(); CheckDisposed();
@ -5607,10 +5575,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentNullException(nameof(itemId)); throw new ArgumentNullException(nameof(itemId));
} }
if (people == null) ArgumentNullException.ThrowIfNull(people);
{
throw new ArgumentNullException(nameof(people));
}
CheckDisposed(); CheckDisposed();
@ -5710,10 +5675,7 @@ AND Type = @InternalPersonType)");
{ {
CheckDisposed(); CheckDisposed();
if (query == null) ArgumentNullException.ThrowIfNull(query);
{
throw new ArgumentNullException(nameof(query));
}
var cmdText = _mediaStreamSaveColumnsSelectQuery; var cmdText = _mediaStreamSaveColumnsSelectQuery;
@ -5766,10 +5728,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentNullException(nameof(id)); throw new ArgumentNullException(nameof(id));
} }
if (streams == null) ArgumentNullException.ThrowIfNull(streams);
{
throw new ArgumentNullException(nameof(streams));
}
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@ -5881,6 +5840,8 @@ AND Type = @InternalPersonType)");
statement.TryBind("@ElPresentFlag" + index, stream.ElPresentFlag); statement.TryBind("@ElPresentFlag" + index, stream.ElPresentFlag);
statement.TryBind("@BlPresentFlag" + index, stream.BlPresentFlag); statement.TryBind("@BlPresentFlag" + index, stream.BlPresentFlag);
statement.TryBind("@DvBlSignalCompatibilityId" + index, stream.DvBlSignalCompatibilityId); statement.TryBind("@DvBlSignalCompatibilityId" + index, stream.DvBlSignalCompatibilityId);
statement.TryBind("@IsHearingImpaired" + index, stream.IsHearingImpaired);
} }
statement.Reset(); statement.Reset();
@ -6092,12 +6053,15 @@ AND Type = @InternalPersonType)");
item.DvBlSignalCompatibilityId = dvBlSignalCompatibilityId; item.DvBlSignalCompatibilityId = dvBlSignalCompatibilityId;
} }
item.IsHearingImpaired = reader.GetBoolean(43);
if (item.Type == MediaStreamType.Subtitle) if (item.Type == MediaStreamType.Subtitle)
{ {
item.LocalizedUndefined = _localization.GetLocalizedString("Undefined"); item.LocalizedUndefined = _localization.GetLocalizedString("Undefined");
item.LocalizedDefault = _localization.GetLocalizedString("Default"); item.LocalizedDefault = _localization.GetLocalizedString("Default");
item.LocalizedForced = _localization.GetLocalizedString("Forced"); item.LocalizedForced = _localization.GetLocalizedString("Forced");
item.LocalizedExternal = _localization.GetLocalizedString("External"); item.LocalizedExternal = _localization.GetLocalizedString("External");
item.LocalizedHearingImpaired = _localization.GetLocalizedString("HearingImpaired");
} }
return item; return item;
@ -6107,10 +6071,7 @@ AND Type = @InternalPersonType)");
{ {
CheckDisposed(); CheckDisposed();
if (query == null) ArgumentNullException.ThrowIfNull(query);
{
throw new ArgumentNullException(nameof(query));
}
var cmdText = _mediaAttachmentSaveColumnsSelectQuery; var cmdText = _mediaAttachmentSaveColumnsSelectQuery;
@ -6152,10 +6113,7 @@ AND Type = @InternalPersonType)");
throw new ArgumentException("Guid can't be empty.", nameof(id)); throw new ArgumentException("Guid can't be empty.", nameof(id));
} }
if (attachments == null) ArgumentNullException.ThrowIfNull(attachments);
{
throw new ArgumentNullException(nameof(attachments));
}
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();

View File

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

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Jellyfin.Api.Helpers;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
@ -18,6 +19,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Lyrics;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
@ -50,6 +52,8 @@ namespace Emby.Server.Implementations.Dto
private readonly IMediaSourceManager _mediaSourceManager; private readonly IMediaSourceManager _mediaSourceManager;
private readonly Lazy<ILiveTvManager> _livetvManagerFactory; private readonly Lazy<ILiveTvManager> _livetvManagerFactory;
private readonly ILyricManager _lyricManager;
public DtoService( public DtoService(
ILogger<DtoService> logger, ILogger<DtoService> logger,
ILibraryManager libraryManager, ILibraryManager libraryManager,
@ -59,7 +63,8 @@ namespace Emby.Server.Implementations.Dto
IProviderManager providerManager, IProviderManager providerManager,
IApplicationHost appHost, IApplicationHost appHost,
IMediaSourceManager mediaSourceManager, IMediaSourceManager mediaSourceManager,
Lazy<ILiveTvManager> livetvManagerFactory) Lazy<ILiveTvManager> livetvManagerFactory,
ILyricManager lyricManager)
{ {
_logger = logger; _logger = logger;
_libraryManager = libraryManager; _libraryManager = libraryManager;
@ -70,6 +75,7 @@ namespace Emby.Server.Implementations.Dto
_appHost = appHost; _appHost = appHost;
_mediaSourceManager = mediaSourceManager; _mediaSourceManager = mediaSourceManager;
_livetvManagerFactory = livetvManagerFactory; _livetvManagerFactory = livetvManagerFactory;
_lyricManager = lyricManager;
} }
private ILiveTvManager LivetvManager => _livetvManagerFactory.Value; private ILiveTvManager LivetvManager => _livetvManagerFactory.Value;
@ -139,6 +145,10 @@ namespace Emby.Server.Implementations.Dto
{ {
LivetvManager.AddInfoToProgramDto(new[] { (item, dto) }, options.Fields, user).GetAwaiter().GetResult(); LivetvManager.AddInfoToProgramDto(new[] { (item, dto) }, options.Fields, user).GetAwaiter().GetResult();
} }
else if (item is Audio)
{
dto.HasLyrics = _lyricManager.HasLyricFile(item);
}
if (item is IItemByName itemByName if (item is IItemByName itemByName
&& options.ContainsField(ItemFields.ItemCounts)) && options.ContainsField(ItemFields.ItemCounts))
@ -182,7 +192,7 @@ namespace Emby.Server.Implementations.Dto
if (options.ContainsField(ItemFields.People)) if (options.ContainsField(ItemFields.People))
{ {
AttachPeople(dto, item); AttachPeople(dto, item, user);
} }
if (options.ContainsField(ItemFields.PrimaryImageAspectRatio)) if (options.ContainsField(ItemFields.PrimaryImageAspectRatio))
@ -503,7 +513,8 @@ namespace Emby.Server.Implementations.Dto
/// </summary> /// </summary>
/// <param name="dto">The dto.</param> /// <param name="dto">The dto.</param>
/// <param name="item">The item.</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. // 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 // This is taking advantage of the fact that they both begin with A
@ -560,6 +571,9 @@ namespace Emby.Server.Implementations.Dto
return null; return null;
} }
}).Where(i => i != null) }).Where(i => i != null)
.Where(i => user == null ?
true :
i.IsVisible(user))
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase) .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.Select(x => x.First()) .Select(x => x.First())
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase); .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);

View File

@ -29,7 +29,7 @@
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.7" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.9" />
<PackageReference Include="Mono.Nat" Version="3.0.3" /> <PackageReference Include="Mono.Nat" Version="3.0.3" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.4" /> <PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.4" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" /> <PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" />

View File

@ -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);
}
}
}

View File

@ -11,7 +11,6 @@ using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session; using MediaBrowser.Model.Session;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.HttpServer namespace Emby.Server.Implementations.HttpServer

View File

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

View File

@ -46,7 +46,6 @@ using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Episode = MediaBrowser.Controller.Entities.TV.Episode; using Episode = MediaBrowser.Controller.Entities.TV.Episode;
using EpisodeInfo = Emby.Naming.TV.EpisodeInfo; using EpisodeInfo = Emby.Naming.TV.EpisodeInfo;
@ -282,10 +281,7 @@ namespace Emby.Server.Implementations.Library
public void RegisterItem(BaseItem item) public void RegisterItem(BaseItem item)
{ {
if (item == null) ArgumentNullException.ThrowIfNull(item);
{
throw new ArgumentNullException(nameof(item));
}
if (item is IItemByName) if (item is IItemByName)
{ {
@ -312,10 +308,7 @@ namespace Emby.Server.Implementations.Library
public void DeleteItem(BaseItem item, DeleteOptions options, bool notifyParentItem) public void DeleteItem(BaseItem item, DeleteOptions options, bool notifyParentItem)
{ {
if (item == null) ArgumentNullException.ThrowIfNull(item);
{
throw new ArgumentNullException(nameof(item));
}
var parent = item.GetOwner() ?? item.GetParent(); 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) public void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem)
{ {
if (item == null) ArgumentNullException.ThrowIfNull(item);
{
throw new ArgumentNullException(nameof(item));
}
if (item.SourceType == SourceType.Channel) if (item.SourceType == SourceType.Channel)
{ {
@ -510,10 +500,7 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(key)); throw new ArgumentNullException(nameof(key));
} }
if (type == null) ArgumentNullException.ThrowIfNull(type);
{
throw new ArgumentNullException(nameof(type));
}
string programDataPath = _configurationManager.ApplicationPaths.ProgramDataPath; string programDataPath = _configurationManager.ApplicationPaths.ProgramDataPath;
if (key.StartsWith(programDataPath, StringComparison.Ordinal)) if (key.StartsWith(programDataPath, StringComparison.Ordinal))
@ -545,10 +532,7 @@ namespace Emby.Server.Implementations.Library
string collectionType = null, string collectionType = null,
LibraryOptions libraryOptions = null) LibraryOptions libraryOptions = null)
{ {
if (fileInfo == null) ArgumentNullException.ThrowIfNull(fileInfo);
{
throw new ArgumentNullException(nameof(fileInfo));
}
var fullPath = fileInfo.FullName; var fullPath = fileInfo.FullName;
@ -1855,10 +1839,7 @@ namespace Emby.Server.Implementations.Library
/// <inheritdoc /> /// <inheritdoc />
public async Task UpdateImagesAsync(BaseItem item, bool forceUpdate = false) public async Task UpdateImagesAsync(BaseItem item, bool forceUpdate = false)
{ {
if (item == null) ArgumentNullException.ThrowIfNull(item);
{
throw new ArgumentNullException(nameof(item));
}
var outdated = forceUpdate var outdated = forceUpdate
? item.ImageInfos.Where(i => i.Path != null).ToArray() ? item.ImageInfos.Where(i => i.Path != null).ToArray()
@ -2297,10 +2278,7 @@ namespace Emby.Server.Implementations.Library
string viewType, string viewType,
string sortName) string sortName)
{ {
if (parent == null) ArgumentNullException.ThrowIfNull(parent);
{
throw new ArgumentNullException(nameof(parent));
}
var name = parent.Name; var name = parent.Name;
var parentId = parent.Id; var parentId = parent.Id;
@ -2529,7 +2507,7 @@ namespace Emby.Server.Implementations.Library
} }
catch (Exception ex) 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; var changed = false;
@ -2766,7 +2744,8 @@ namespace Emby.Server.Implementations.Library
public List<Person> GetPeopleItems(InternalPeopleQuery query) public List<Person> GetPeopleItems(InternalPeopleQuery query)
{ {
return _itemRepository.GetPeopleNames(query).Select(i => return _itemRepository.GetPeopleNames(query)
.Select(i =>
{ {
try try
{ {
@ -2777,7 +2756,12 @@ namespace Emby.Server.Implementations.Library
_logger.LogError(ex, "Error getting person"); _logger.LogError(ex, "Error getting person");
return null; 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) public List<string> GetPeopleNames(InternalPeopleQuery query)
@ -2978,10 +2962,7 @@ namespace Emby.Server.Implementations.Library
private void AddMediaPathInternal(string virtualFolderName, MediaPathInfo pathInfo, bool saveLibraryOptions) private void AddMediaPathInternal(string virtualFolderName, MediaPathInfo pathInfo, bool saveLibraryOptions)
{ {
if (pathInfo == null) ArgumentNullException.ThrowIfNull(pathInfo);
{
throw new ArgumentNullException(nameof(pathInfo));
}
var path = pathInfo.Path; var path = pathInfo.Path;
@ -3028,10 +3009,7 @@ namespace Emby.Server.Implementations.Library
public void UpdateMediaPath(string virtualFolderName, MediaPathInfo mediaPath) public void UpdateMediaPath(string virtualFolderName, MediaPathInfo mediaPath)
{ {
if (mediaPath == null) ArgumentNullException.ThrowIfNull(mediaPath);
{
throw new ArgumentNullException(nameof(mediaPath));
}
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath; var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);

View File

@ -322,10 +322,7 @@ namespace Emby.Server.Implementations.Library
public List<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null) public List<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null)
{ {
if (item == null) ArgumentNullException.ThrowIfNull(item);
{
throw new ArgumentNullException(nameof(item));
}
var hasMediaSources = (IHasMediaSources)item; var hasMediaSources = (IHasMediaSources)item;

View File

@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -18,7 +19,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers.Audio namespace Emby.Server.Implementations.Library.Resolvers.Audio
{ {
/// <summary> /// <summary>
/// Class MusicAlbumResolver. /// The music album resolver.
/// </summary> /// </summary>
public class MusicAlbumResolver : ItemResolver<MusicAlbum> public class MusicAlbumResolver : ItemResolver<MusicAlbum>
{ {
@ -82,7 +83,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
/// </summary> /// </summary>
/// <param name="path">The path to check.</param> /// <param name="path">The path to check.</param>
/// <param name="directoryService">The directory service.</param> /// <param name="directoryService">The directory service.</param>
/// <returns><c>true</c> if the provided path points to a music album, <c>false</c> otherwise.</returns> /// <returns><c>true</c> if the provided path points to a music album; otherwise, <c>false</c>.</returns>
public bool IsMusicAlbum(string path, IDirectoryService directoryService) public bool IsMusicAlbum(string path, IDirectoryService directoryService)
{ {
return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService); return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService);
@ -95,10 +96,19 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
/// <returns><c>true</c> if [is music album] [the specified args]; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if [is music album] [the specified args]; otherwise, <c>false</c>.</returns>
private bool IsMusicAlbum(ItemResolveArgs args) private bool IsMusicAlbum(ItemResolveArgs args)
{ {
// Args points to an album if parent is an Artist folder or it directly contains music
if (args.IsDirectory) if (args.IsDirectory)
{ {
// if (args.Parent is MusicArtist) return true; // saves us from testing children twice // If args is a artist subfolder it's not a music album
foreach (var subfolder in _namingOptions.ArtistSubfolders)
{
if (Path.GetDirectoryName(args.Path.AsSpan()).Equals(subfolder, StringComparison.OrdinalIgnoreCase))
{
_logger.LogDebug("Found release folder: {Path}", args.Path);
return false;
}
}
// If args contains music it's a music album
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService)) if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService))
{ {
return true; return true;
@ -111,22 +121,23 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
/// <summary> /// <summary>
/// Determine if the supplied list contains what we should consider music. /// Determine if the supplied list contains what we should consider music.
/// </summary> /// </summary>
/// <returns><c>true</c> if the provided path list contains music; otherwise, <c>false</c>.</returns>
private bool ContainsMusic( private bool ContainsMusic(
ICollection<FileSystemMetadata> list, ICollection<FileSystemMetadata> list,
bool allowSubfolders, bool allowSubfolders,
IDirectoryService directoryService) IDirectoryService directoryService)
{ {
// check for audio files before digging down into directories // Check for audio files before digging down into directories
var foundAudioFile = list.Any(fileSystemInfo => !fileSystemInfo.IsDirectory && AudioFileParser.IsAudioFile(fileSystemInfo.FullName, _namingOptions)); var foundAudioFile = list.Any(fileSystemInfo => !fileSystemInfo.IsDirectory && AudioFileParser.IsAudioFile(fileSystemInfo.FullName, _namingOptions));
if (foundAudioFile) if (foundAudioFile)
{ {
// at least one audio file exists // At least one audio file exists
return true; return true;
} }
if (!allowSubfolders) if (!allowSubfolders)
{ {
// not music since no audio file exists and we're not looking into subfolders // Not music since no audio file exists and we're not looking into subfolders
return false; return false;
} }

View File

@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers.Audio namespace Emby.Server.Implementations.Library.Resolvers.Audio
{ {
/// <summary> /// <summary>
/// Class MusicArtistResolver. /// The music artist resolver.
/// </summary> /// </summary>
public class MusicArtistResolver : ItemResolver<MusicArtist> public class MusicArtistResolver : ItemResolver<MusicArtist>
{ {
@ -23,8 +23,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MusicArtistResolver"/> class. /// Initializes a new instance of the <see cref="MusicArtistResolver"/> class.
/// </summary> /// </summary>
/// <param name="logger">The logger for the created <see cref="MusicAlbumResolver"/> instances.</param> /// <param name="logger">Instance of the <see cref="MusicAlbumResolver"/> interface.</param>
/// <param name="namingOptions">The naming options.</param> /// <param name="namingOptions">The <see cref="NamingOptions"/>.</param>
public MusicArtistResolver( public MusicArtistResolver(
ILogger<MusicAlbumResolver> logger, ILogger<MusicAlbumResolver> logger,
NamingOptions namingOptions) NamingOptions namingOptions)
@ -40,10 +40,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
public override ResolverPriority Priority => ResolverPriority.Second; public override ResolverPriority Priority => ResolverPriority.Second;
/// <summary> /// <summary>
/// Resolves the specified args. /// Resolves the specified resolver arguments.
/// </summary> /// </summary>
/// <param name="args">The args.</param> /// <param name="args">The resolver arguments.</param>
/// <returns>MusicArtist.</returns> /// <returns>A <see cref="MusicArtist"/>.</returns>
protected override MusicArtist Resolve(ItemResolveArgs args) protected override MusicArtist Resolve(ItemResolveArgs args)
{ {
if (!args.IsDirectory) if (!args.IsDirectory)
@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase); var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase);
// If there's a collection type and it's not music, it can't be a series // If there's a collection type and it's not music, it can't be a music artist
if (!isMusicMediaFolder) if (!isMusicMediaFolder)
{ {
return null; return null;
@ -82,14 +82,24 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
var albumResolver = new MusicAlbumResolver(_logger, _namingOptions); var albumResolver = new MusicAlbumResolver(_logger, _namingOptions);
// If we contain an album assume we are an artist folder
var directories = args.FileSystemChildren.Where(i => i.IsDirectory); var directories = args.FileSystemChildren.Where(i => i.IsDirectory);
var result = Parallel.ForEach(directories, (fileSystemInfo, state) => var result = Parallel.ForEach(directories, (fileSystemInfo, state) =>
{ {
// If we contain a artist subfolder assume we are an artist folder
foreach (var subfolder in _namingOptions.ArtistSubfolders)
{
if (fileSystemInfo.Name.Equals(subfolder, StringComparison.OrdinalIgnoreCase))
{
// Stop once we see an artist subfolder
state.Stop();
}
}
// If we contain a music album assume we are an artist folder
if (albumResolver.IsMusicAlbum(fileSystemInfo.FullName, directoryService)) if (albumResolver.IsMusicAlbum(fileSystemInfo.FullName, directoryService))
{ {
// stop once we see a music album // Stop once we see a music album
state.Stop(); state.Stop();
} }
}); });

View File

@ -387,7 +387,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (!string.IsNullOrEmpty(item.Path)) 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"); var imdbid = item.Path.AsSpan().GetAttributeValue("imdbid");
if (!string.IsNullOrWhiteSpace(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) ?? var result = ResolveVideos<T>(parent, fileSystemEntries, SupportsMultiVersion, collectionType, parseName) ??
new MultiItemResolverResult(); 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 videoPath = result.Items[0].Path;
var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(videoPath, i.Name)); var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(videoPath, i.Name));

View File

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

View File

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

View File

@ -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) 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) private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, ActiveRecordingInfo activeRecordingInfo)
{ {
if (timer == null) ArgumentNullException.ThrowIfNull(timer);
{
throw new ArgumentNullException(nameof(timer));
}
LiveTvProgram programInfo = null; LiveTvProgram programInfo = null;
@ -2221,6 +2218,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{ {
continue; continue;
} }
// Skip ShowId without SubKey from duplicate removal actions - https://github.com/jellyfin/jellyfin/issues/5856
if (group.Key.EndsWith("0000"))
{
continue;
}
HandleDuplicateShowIds(groupTimers); HandleDuplicateShowIds(groupTimers);
} }
@ -2347,10 +2350,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer) private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer)
{ {
if (seriesTimer == null) ArgumentNullException.ThrowIfNull(seriesTimer);
{
throw new ArgumentNullException(nameof(seriesTimer));
}
var query = new InternalItemsQuery var query = new InternalItemsQuery
{ {

View File

@ -13,6 +13,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using Jellyfin.Extensions.Json; using Jellyfin.Extensions.Json;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
@ -297,7 +298,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
else else
{ {
_taskCompletionSource.TrySetException( _taskCompletionSource.TrySetException(
new Exception( new FfmpegException(
string.Format( string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
"Recording for {0} failed. Exit code {1}", "Recording for {0} failed. Exit code {1}",

View File

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

View File

@ -2,8 +2,8 @@
using System; using System;
using System.Globalization; using System.Globalization;
using MediaBrowser.Controller.LiveTv;
using System.Text; using System.Text;
using MediaBrowser.Controller.LiveTv;
namespace Emby.Server.Implementations.LiveTv.EmbyTV namespace Emby.Server.Implementations.LiveTv.EmbyTV
{ {
@ -56,7 +56,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
} }
tmpName += " " + info.EpisodeTitle; tmpName += " " + info.EpisodeTitle;
// Since the filename will be used with file ext. (.mp4, .ts, etc) // Since the filename will be used with file ext. (.mp4, .ts, etc)
if (Encoding.UTF8.GetByteCount(tmpName) < 250) if (Encoding.UTF8.GetByteCount(tmpName) < 250)
{ {
name = tmpName; name = tmpName;

View File

@ -20,6 +20,7 @@ using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using Jellyfin.Extensions.Json; using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -591,13 +592,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings
} }
catch (HttpRequestException ex) 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; throw;
@ -662,7 +660,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return root.Token; 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) private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken)
@ -697,7 +695,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (string.IsNullOrEmpty(token)) if (string.IsNullOrEmpty(token))
{ {
throw new Exception("token required"); throw new ArgumentException("token required");
} }
_logger.LogInformation("Headends on account "); _logger.LogInformation("Headends on account ");
@ -768,14 +766,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var listingsId = info.ListingsId; var listingsId = info.ListingsId;
if (string.IsNullOrEmpty(listingsId)) if (string.IsNullOrEmpty(listingsId))
{ {
throw new Exception("ListingsId required"); throw new ArgumentException("ListingsId required");
} }
var token = await GetToken(info, cancellationToken).ConfigureAwait(false); var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
if (string.IsNullOrEmpty(token)) if (string.IsNullOrEmpty(token))
{ {
throw new Exception("token required"); throw new ArgumentException("token required");
} }
using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId); using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId);

View File

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

View File

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

View File

@ -28,6 +28,7 @@
"HeaderLiveTV": "Live TV", "HeaderLiveTV": "Live TV",
"HeaderNextUp": "Next Up", "HeaderNextUp": "Next Up",
"HeaderRecordingGroups": "Recording Groups", "HeaderRecordingGroups": "Recording Groups",
"HearingImpaired": "Hearing Impaired",
"HomeVideos": "Home Videos", "HomeVideos": "Home Videos",
"Inherit": "Inherit", "Inherit": "Inherit",
"ItemAddedWithName": "{0} was added to the library", "ItemAddedWithName": "{0} was added to the library",

View File

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

View File

@ -122,5 +122,6 @@
"TaskOptimizeDatabase": "Optimiziraj bazu podataka", "TaskOptimizeDatabase": "Optimiziraj bazu podataka",
"External": "Vanjski", "External": "Vanjski",
"TaskKeyframeExtractorDescription": "Izvlačenje ključnih okvira iz videozapisa za stvaranje objektivnije HLS liste za reprodukciju. Pokretanje ovog zadatka može potrajati.", "TaskKeyframeExtractorDescription": "Izvlačenje ključnih okvira iz videozapisa za stvaranje objektivnije HLS liste za reprodukciju. Pokretanje ovog zadatka može potrajati.",
"TaskKeyframeExtractor": "Izvoditelj ključnog okvira" "TaskKeyframeExtractor": "Izvoditelj ključnog okvira",
"TaskOptimizeDatabaseDescription": "Sažima bazu podataka i uklanja prazan prostor. Pokretanje ovog zadatka, može poboljšati performanse nakon provođenja indeksiranja biblioteke ili provođenja drugih promjena koje utječu na bazu podataka."
} }

View File

@ -3,14 +3,14 @@
"AppDeviceValues": "앱: {0}, 장치: {1}", "AppDeviceValues": "앱: {0}, 장치: {1}",
"Application": "애플리케이션", "Application": "애플리케이션",
"Artists": "아티스트", "Artists": "아티스트",
"AuthenticationSucceededWithUserName": "{0}이 성공적으로 인증됨", "AuthenticationSucceededWithUserName": "{0}이(가) 성공적으로 인증됨",
"Books": "도서", "Books": "도서",
"CameraImageUploadedFrom": "{0}에서 새로운 카메라 이미지가 업로드됨", "CameraImageUploadedFrom": "{0}에서 새로운 카메라 이미지가 업로드됨",
"Channels": "채널", "Channels": "채널",
"ChapterNameValue": "챕터 {0}", "ChapterNameValue": "챕터 {0}",
"Collections": "컬렉션", "Collections": "컬렉션",
"DeviceOfflineWithName": "{0}의 연결 끊김", "DeviceOfflineWithName": "{0}의 연결 끊김",
"DeviceOnlineWithName": "{0}이 연결됨", "DeviceOnlineWithName": "{0}이(가) 연결됨",
"FailedLoginAttemptWithUserName": "{0}에서 로그인 실패", "FailedLoginAttemptWithUserName": "{0}에서 로그인 실패",
"Favorites": "즐겨찾기", "Favorites": "즐겨찾기",
"Folders": "폴더", "Folders": "폴더",
@ -120,5 +120,8 @@
"Forced": "강제하기", "Forced": "강제하기",
"Default": "기본 설정", "Default": "기본 설정",
"TaskOptimizeDatabaseDescription": "데이터베이스를 압축하고 사용 가능한 공간을 늘립니다. 라이브러리를 검색한 후 이 작업을 실행하거나 데이터베이스 수정같은 비슷한 작업을 수행하면 성능이 향상될 수 있습니다.", "TaskOptimizeDatabaseDescription": "데이터베이스를 압축하고 사용 가능한 공간을 늘립니다. 라이브러리를 검색한 후 이 작업을 실행하거나 데이터베이스 수정같은 비슷한 작업을 수행하면 성능이 향상될 수 있습니다.",
"TaskOptimizeDatabase": "데이터베이스 최적화" "TaskOptimizeDatabase": "데이터베이스 최적화",
"TaskKeyframeExtractorDescription": "비디오 파일에서 키프레임을 추출하여 더 정확한 HLS 재생 목록을 만듭니다. 이 작업은 오랫동안 진행될 수 있습니다.",
"TaskKeyframeExtractor": "키프레임 추출",
"External": "외부"
} }

View File

@ -84,7 +84,7 @@
"CameraImageUploadedFrom": "Jauns kameras attēls ir ticis augšupielādēts no {0}", "CameraImageUploadedFrom": "Jauns kameras attēls ir ticis augšupielādēts no {0}",
"Books": "Grāmatas", "Books": "Grāmatas",
"Artists": "Izpildītāji", "Artists": "Izpildītāji",
"Albums": "Albumi", "Albums": "Albūmi",
"ProviderValue": "Provider: {0}", "ProviderValue": "Provider: {0}",
"HeaderFavoriteSongs": "Dziesmu Favorīti", "HeaderFavoriteSongs": "Dziesmu Favorīti",
"HeaderFavoriteShows": "Raidījumu Favorīti", "HeaderFavoriteShows": "Raidījumu Favorīti",
@ -117,7 +117,8 @@
"TaskCleanActivityLogDescription": "Nodzēš darbību žurnāla ierakstus, kuri ir vecāki par doto vecumu.", "TaskCleanActivityLogDescription": "Nodzēš darbību žurnāla ierakstus, kuri ir vecāki par doto vecumu.",
"TaskCleanActivityLog": "Notīrīt Darbību Žurnālu", "TaskCleanActivityLog": "Notīrīt Darbību Žurnālu",
"Undefined": "Nenoteikts", "Undefined": "Nenoteikts",
"Default": "Noklusējums", "Default": "Noklusējuma",
"TaskOptimizeDatabaseDescription": "Saspiež datubāzi un atbrīvo atmiņu. Uzdevum palaišana pēc bibliotēku skenēšanas vai citām, ar datubāzi saistītām, izmaiņām iespējams uzlabos ātrdarbību.", "TaskOptimizeDatabaseDescription": "Saspiež datubāzi un atbrīvo atmiņu. Uzdevum palaišana pēc bibliotēku skenēšanas vai citām, ar datubāzi saistītām, izmaiņām iespējams uzlabos ātrdarbību.",
"TaskOptimizeDatabase": "Optimizēt datubāzi" "TaskOptimizeDatabase": "Optimizēt datubāzi",
"External": "Ārējais"
} }

View File

@ -64,9 +64,9 @@
"CameraImageUploadedFrom": "Нова слика од камера беше поставена од {0}", "CameraImageUploadedFrom": "Нова слика од камера беше поставена од {0}",
"Books": "Книги", "Books": "Книги",
"AuthenticationSucceededWithUserName": "{0} успешно поврзан", "AuthenticationSucceededWithUserName": "{0} успешно поврзан",
"Artists": "Изведувач", "Artists": "Изведувачи",
"Application": "Апликација", "Application": "Апликација",
"AppDeviceValues": "Аплиакција: {0}, Уред: {1}", "AppDeviceValues": "Апликација: {0}, Уред: {1}",
"Albums": "Албуми", "Albums": "Албуми",
"VersionNumber": "Верзија {0}", "VersionNumber": "Верзија {0}",
"ValueSpecialEpisodeName": "Специјално - {0}", "ValueSpecialEpisodeName": "Специјално - {0}",
@ -100,5 +100,27 @@
"TasksMaintenanceCategory": "Одржување", "TasksMaintenanceCategory": "Одржување",
"Undefined": "Недефинирано", "Undefined": "Недефинирано",
"Forced": "Принудно", "Forced": "Принудно",
"Default": "Зададено" "Default": "Зададено",
"TaskKeyframeExtractorDescription": "Извлекува клучни рамки од видео фајлови за да се направат попрецизни HLS плејлисти. Оваа задача може да работи многу долго време.",
"TaskKeyframeExtractor": "Извлекувач на клучни рамки",
"TaskOptimizeDatabaseDescription": "Компактира датабазата и смалува празното место. Извршувањето на оваа задача по скенирање на библиотеката или правење други промени што прават модификации на датабазата може да подобри перформансите.",
"TaskOptimizeDatabase": "Оптимизирај датабаза",
"TaskDownloadMissingSubtitlesDescription": "Пребарува интернет за преводи што недостиваат според метадата конфигурација.",
"TaskDownloadMissingSubtitles": "Симни преводи што недостигаат",
"TaskRefreshChannelsDescription": "Ажурирај информации за интернет канали.",
"TaskRefreshChannels": "Ажурирај Канали",
"TaskCleanTranscodeDescription": "Избриши транскодирани фајлови постари од еден ден.",
"TaskCleanTranscode": "Исчисти Директориум за Транскодирање",
"TaskUpdatePluginsDescription": "Симни и инсталирај ажурирања за плагини што се конфигурирани за автоматско ажурирање.",
"TaskUpdatePlugins": "Ажурирај Плагини",
"TaskRefreshPeopleDescription": "Ажурирај метадата за акери и директори во вашата медиска библиотека.",
"TaskRefreshPeople": "Ажурирајте ги Луѓето",
"TaskCleanLogsDescription": "Избриши лог фајлови постари од {0} денови.",
"TaskCleanLogs": "Избриши Директориум на Логови",
"TaskRefreshLibraryDescription": "Скенирајте ја вашата медиска библиотека за нови фајлови и ажурирај метадата.",
"TaskRefreshLibrary": "Скенирај Медиумска Библиотека",
"TaskRefreshChapterImagesDescription": "Создава тамбнеил за видеата шти имаат поглавја.",
"TaskCleanActivityLogDescription": "Избришува логови на активности постари од определеното време.",
"TaskCleanActivityLog": "Избриши Лог на Активности",
"External": "Надворешен"
} }

View File

@ -6,97 +6,97 @@
"Artists": "အနုပညာရှင်များ", "Artists": "အနုပညာရှင်များ",
"Albums": "သီချင်းအခွေများ", "Albums": "သီချင်းအခွေများ",
"TaskOptimizeDatabaseDescription": "ဒေတာဘေ့စ်ကို ကျစ်လစ်စေပြီး နေရာလွတ်များကို ဖြတ်တောက်ပေးသည်။ စာကြည့်တိုက်ကို စကင်န်ဖတ်ပြီးနောက် ဤလုပ်ငန်းကို လုပ်ဆောင်ခြင်း သို့မဟုတ် ဒေတာဘေ့စ်မွမ်းမံမှုများ စွမ်းဆောင်ရည်ကို မြှင့်တင်ပေးနိုင်သည်ဟု ရည်ညွှန်းသော အခြားပြောင်းလဲမှုများကို လုပ်ဆောင်ခြင်း။.", "TaskOptimizeDatabaseDescription": "ဒေတာဘေ့စ်ကို ကျစ်လစ်စေပြီး နေရာလွတ်များကို ဖြတ်တောက်ပေးသည်။ စာကြည့်တိုက်ကို စကင်န်ဖတ်ပြီးနောက် ဤလုပ်ငန်းကို လုပ်ဆောင်ခြင်း သို့မဟုတ် ဒေတာဘေ့စ်မွမ်းမံမှုများ စွမ်းဆောင်ရည်ကို မြှင့်တင်ပေးနိုင်သည်ဟု ရည်ညွှန်းသော အခြားပြောင်းလဲမှုများကို လုပ်ဆောင်ခြင်း။.",
"TaskOptimizeDatabase": "ဒေတာဘေ့စ်ကို အကောင်းဆုံးဖြစ်အောင်လုပ်ပါ", "TaskOptimizeDatabase": "ဒေတာဘေ့စ်ကို အကောင်းဆုံးဖြစ်အောင်လုပ်ပါ",
"TaskDownloadMissingSubtitlesDescription": "မက်တာဒေတာ ဖွဲ့စည်းမှုပုံစံအပေါ် အခြေခံ၍ ပျောက်ဆုံးနေသော စာတန်းထိုးများအတွက် အင်တာနက်ကို ရှာဖွေသည်။", "TaskDownloadMissingSubtitlesDescription": "မက်တာဒေတာ ဖွဲ့စည်းမှုပုံစံအပေါ် အခြေခံ၍ ပျောက်ဆုံးနေသော စာတန်းထိုးများအတွက် အင်တာနက်ကို ရှာဖွေသည်။",
"TaskDownloadMissingSubtitles": "ပျောက်ဆုံးနေသော စာတန်းထိုးများကို ဒေါင်းလုဒ်လုပ်ပါ", "TaskDownloadMissingSubtitles": "ပျောက်ဆုံးနေသော စာတန်းထိုးများကို ဒေါင်းလုဒ်လုပ်ပါ",
"TaskRefreshChannelsDescription": "အင်တာနက်ချန်နယ်အချက်အလက်ကို ပြန်လည်စတင်သည်။", "TaskRefreshChannelsDescription": "အင်တာနက်ချန်နယ်အချက်အလက်ကို ပြန်လည်စတင်သည်။",
"TaskRefreshChannels": "ချန်နယ်များကို ပြန်လည်စတင်ပါ", "TaskRefreshChannels": "ချန်နယ်များကို ပြန်လည်စတင်ပါ",
"TaskCleanTranscodeDescription": "သက်တမ်း တစ်ရက်ထက်ပိုသော အသွင်ပြောင်းကုဒ်ဖိုင်များကို ဖျက်ပါ။", "TaskCleanTranscodeDescription": "သက်တမ်း တစ်ရက်ထက်ပိုသော အသွင်ပြောင်းကုဒ်ဖိုင်များကို ဖျက်ပါ။",
"TaskCleanTranscode": "Transcode လမ်းညွှန်ကို သန့်ရှင်းပါ", "TaskCleanTranscode": "Transcode လမ်းညွှန်ကို သန့်ရှင်းပါ",
"TaskUpdatePluginsDescription": "အလိုအလျောက် အပ်ဒိတ်လုပ်ရန် စီစဉ်ထားသော ပလပ်အင်များအတွက် အပ်ဒိတ်များကို ဒေါင်းလုဒ်လုပ်ပြီး ထည့်သွင်းပါ။", "TaskUpdatePluginsDescription": "အလိုအလျောက် အပ်ဒိတ်လုပ်ရန် စီစဉ်ထားသော ပလပ်အင်များအတွက် အပ်ဒိတ်များကို ဒေါင်းလုဒ်လုပ်ပြီး ထည့်သွင်းပါ။",
"TaskUpdatePlugins": "ပလပ်အင်များကို အပ်ဒိတ်လုပ်ပါ", "TaskUpdatePlugins": "ပလပ်အင်များကို အပ်ဒိတ်လုပ်ပါ",
"TaskRefreshPeopleDescription": "သင့်မီဒီယာစာကြည့်တိုက်ရှိ သရုပ်ဆောင်များနှင့် ဒါရိုက်တာများအတွက် မက်တာဒေတာကို အပ်ဒိတ်လုပ်ပါ။", "TaskRefreshPeopleDescription": "သင့်မီဒီယာစာကြည့်တိုက်ရှိ သရုပ်ဆောင်များနှင့် ဒါရိုက်တာများအတွက် မက်တာဒေတာကို အပ်ဒိတ်လုပ်ပါ။",
"TaskRefreshPeople": "လူများကို ပြန်လည်ဆန်းသစ်ပါ", "TaskRefreshPeople": "လူများကို ပြန်လည်ဆန်းသစ်ပါ",
"TaskCleanLogsDescription": "{0} ရက်ထက်ပိုသော မှတ်တမ်းဖိုင်များကို ဖျက်သည်။", "TaskCleanLogsDescription": "{0} ရက်ထက်ပိုသော မှတ်တမ်းဖိုင်များကို ဖျက်သည်။",
"TaskCleanLogs": "မှတ်တမ်းလမ်းညွှန်ကို သန့်ရှင်းပါ", "TaskCleanLogs": "မှတ်တမ်းလမ်းညွှန်ကို သန့်ရှင်းပါ",
"TaskRefreshLibraryDescription": "သင့်မီဒီယာဒစ်ဂျစ်တိုက်ကို ဖိုင်အသစ်များရှိမရှိ စကင်န်ဖတ်ပြီး ဖိုင်ရဲ့အကြောင်းအရာများ ကို ပြန်ပြုပြင်မွမ်းမံပါ။", "TaskRefreshLibraryDescription": "သင့်မီဒီယာဒစ်ဂျစ်တိုက်ကို ဖိုင်အသစ်များရှိမရှိ စကင်န်ဖတ်ပြီး ဖိုင်ရဲ့အကြောင်းအရာများ ကို ပြန်ပြုပြင်မွမ်းမံပါ။",
"TaskRefreshLibrary": "မီဒီယာစာကြည့်တိုက်ကို စကင်န်ဖတ်ပါ", "TaskRefreshLibrary": "မီဒီယာစာကြည့်တိုက်ကို စကင်န်ဖတ်ပါ",
"TaskRefreshChapterImagesDescription": "အခန်းများပါရှိသော ဗီဒီယိုများအတွက် ပုံသေးများကို ဖန်တီးပါ။", "TaskRefreshChapterImagesDescription": "အခန်းများပါရှိသော ဗီဒီယိုများအတွက် ပုံသေးများကို ဖန်တီးပါ။",
"TaskRefreshChapterImages": "အခန်းတစ်ခုစီ ပုံများကို ထုတ်ယူပါ", "TaskRefreshChapterImages": "အခန်းတစ်ခုစီ ပုံများကို ထုတ်ယူပါ",
"TaskCleanCacheDescription": "စနစ်မှ မလိုအပ်တော့သော ကက်ရှ်ဖိုင်များကို ဖျက်ပါ။.", "TaskCleanCacheDescription": "စနစ်မှ မလိုအပ်တော့သော ကက်ရှ်ဖိုင်များကို ဖျက်ပါ။.",
"TaskCleanCache": "Cache Directory ကို ရှင်းပါ", "TaskCleanCache": "Cache Directory ကို ရှင်းပါ",
"TaskCleanActivityLogDescription": "စီစဉ်သတ်မှတ်ထားသော အသက်ထက် ပိုကြီးသော လုပ်ဆောင်ချက်မှတ်တမ်းများကို ဖျက်ပါ။", "TaskCleanActivityLogDescription": "စီစဉ်သတ်မှတ်ထားသော အသက်ထက် ပိုကြီးသော လုပ်ဆောင်ချက်မှတ်တမ်းများကို ဖျက်ပါ။",
"TaskCleanActivityLog": "လုပ်ဆောင်ချက်မှတ်တမ်းကို ရှင်းလင်းပါ", "TaskCleanActivityLog": "လုပ်ဆောင်ချက်မှတ်တမ်းကို ရှင်းလင်းပါ",
"TasksChannelsCategory": "အင်တာနက် ချန်နယ်လိုင်းများ", "TasksChannelsCategory": "အင်တာနက် ချန်နယ်လိုင်းများ",
"TasksApplicationCategory": "အပလီကေးရှင်း", "TasksApplicationCategory": "အပလီကေးရှင်း",
"TasksLibraryCategory": "မီဒီယာတိုက်", "TasksLibraryCategory": "မီဒီယာတိုက်",
"TasksMaintenanceCategory": "ပြုပြင် ထိန်းသိမ်းခြင်း", "TasksMaintenanceCategory": "ပြုပြင် ထိန်းသိမ်းခြင်း",
"VersionNumber": "ဗားရှင်း {0}", "VersionNumber": "ဗားရှင်း {0}",
"ValueSpecialEpisodeName": "အထူး- {0}", "ValueSpecialEpisodeName": "အထူး- {0}",
"ValueHasBeenAddedToLibrary": "{0} ကို သင့်မီဒီယာဒစ်ဂျစ်တိုက်သို့ ပေါင်းထည့်လိုက်ပါပြီ", "ValueHasBeenAddedToLibrary": "{0} ကို သင့်မီဒီယာဒစ်ဂျစ်တိုက်သို့ ပေါင်းထည့်လိုက်ပါပြီ",
"UserStoppedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ဖွင့်ပြီးပါပြီ", "UserStoppedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ဖွင့်ပြီးပါပြီ",
"UserStartedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ပြသနေသည်", "UserStartedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ပြသနေသည်",
"UserPolicyUpdatedWithName": "{0} အတွက် အသုံးပြုသူမူဝါဒကို အပ်ဒိတ်လုပ်ပြီးပါပြီ", "UserPolicyUpdatedWithName": "{0} အတွက် အသုံးပြုသူမူဝါဒကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"UserPasswordChangedWithName": "အသုံးပြုသူ {0} အတွက် စကားဝှက်ကို ပြောင်းထားသည်", "UserPasswordChangedWithName": "အသုံးပြုသူ {0} အတွက် စကားဝှက်ကို ပြောင်းထားသည်",
"UserOnlineFromDevice": "{0} သည် {1} မှ အွန်လိုင်းဖြစ်သည်", "UserOnlineFromDevice": "{0} သည် {1} မှ အွန်လိုင်းဖြစ်သည်",
"UserOfflineFromDevice": "{0} သည် {1} မှ ချိတ်ဆက်မှုပြတ်တောက်သွားသည်", "UserOfflineFromDevice": "{0} သည် {1} မှ ချိတ်ဆက်မှုပြတ်တောက်သွားသည်",
"UserLockedOutWithName": "အသုံးပြုသူ {0} အား လော့ခ်ချထားသည်", "UserLockedOutWithName": "အသုံးပြုသူ {0} အား လော့ခ်ချထားသည်",
"UserDownloadingItemWithValues": "{0} သည် {1} ကို ဒေါင်းလုဒ်လုပ်နေသည်", "UserDownloadingItemWithValues": "{0} သည် {1} ကို ဒေါင်းလုဒ်လုပ်နေသည်",
"UserDeletedWithName": "အသုံးပြုသူ {0} ကို ဖျက်လိုက်ပါပြီ", "UserDeletedWithName": "အသုံးပြုသူ {0} ကို ဖျက်လိုက်ပါပြီ",
"UserCreatedWithName": "အသုံးပြုသူ {0} ကို ဖန်တီးပြီးပါပြီ", "UserCreatedWithName": "အသုံးပြုသူ {0} ကို ဖန်တီးပြီးပါပြီ",
"User": "အသုံးပြုသူ", "User": "အသုံးပြုသူ",
"Undefined": "သတ်မှတ်မထားသော", "Undefined": "သတ်မှတ်မထားသော",
"TvShows": "တီဗီ ဇာတ်လမ်းတွဲများ", "TvShows": "တီဗီ ဇာတ်လမ်းတွဲများ",
"System": "စနစ်", "System": "စနစ်",
"Sync": "ထပ်တူကျသည်။", "Sync": "ထပ်တူကျသည်။",
"SubtitleDownloadFailureFromForItem": "{1} အတွက် {0} မှ စာတန်းထိုးများ ဒေါင်းလုဒ်လုပ်ခြင်း မအောင်မြင်ပါ", "SubtitleDownloadFailureFromForItem": "{1} အတွက် {0} မှ စာတန်းထိုးများ ဒေါင်းလုဒ်လုပ်ခြင်း မအောင်မြင်ပါ",
"StartupEmbyServerIsLoading": "Jellyfin ဆာဗာကို အသင့်ပြင်နေပါသည်။ ခဏနေ ထပ်စမ်းကြည့်ပါ။", "StartupEmbyServerIsLoading": "Jellyfin ဆာဗာကို အသင့်ပြင်နေပါသည်။ ခဏနေ ထပ်စမ်းကြည့်ပါ။",
"Songs": "သီချင်းများ", "Songs": "သီချင်းများ",
"Shows": "ဇာတ်လမ်းတွဲများ", "Shows": "ဇာတ်လမ်းတွဲများ",
"ServerNameNeedsToBeRestarted": "{0} ကို ပြန်လည်စတင်ရန် လိုအပ်သည်", "ServerNameNeedsToBeRestarted": "{0} ကို ပြန်လည်စတင်ရန် လိုအပ်သည်",
"ScheduledTaskStartedWithName": "{0} စတင်ခဲ့သည်", "ScheduledTaskStartedWithName": "{0} စတင်ခဲ့သည်",
"ScheduledTaskFailedWithName": "{0} မအောင်မြင်ပါ", "ScheduledTaskFailedWithName": "{0} မအောင်မြင်ပါ",
"ProviderValue": "ဝန်ဆောင်မှုပေးသူ- {0}", "ProviderValue": "ဝန်ဆောင်မှုပေးသူ- {0}",
"PluginUpdatedWithName": "ပလပ်ခ်အင် {0} ကို အပ်ဒိတ်လုပ်ထားသည်", "PluginUpdatedWithName": "ပလပ်ခ်အင် {0} ကို အပ်ဒိတ်လုပ်ထားသည်",
"PluginUninstalledWithName": "ပလပ်ခ်အင် {0} ကို ဖြုတ်လိုက်ပါပြီ", "PluginUninstalledWithName": "ပလပ်ခ်အင် {0} ကို ဖြုတ်လိုက်ပါပြီ",
"PluginInstalledWithName": "ပလပ်ခ်အင် {0} ကို ထည့်သွင်းခဲ့သည်", "PluginInstalledWithName": "ပလပ်ခ်အင် {0} ကို ထည့်သွင်းခဲ့သည်",
"Plugin": "ပလပ်အင်", "Plugin": "ပလပ်အင်",
"Playlists": "အစီအစဉ်များ", "Playlists": "အစီအစဉ်များ",
"Photos": "ဓာတ်ပုံများ", "Photos": "ဓာတ်ပုံများ",
"NotificationOptionVideoPlaybackStopped": "ဗီဒီယိုဖွင့်ခြင်း ရပ်သွားသည်", "NotificationOptionVideoPlaybackStopped": "ဗီဒီယိုဖွင့်ခြင်း ရပ်သွားသည်",
"NotificationOptionVideoPlayback": "ဗီဒီယိုဖွင့်ခြင်း စတင်ပါပြီ", "NotificationOptionVideoPlayback": "ဗီဒီယိုဖွင့်ခြင်း စတင်ပါပြီ",
"NotificationOptionUserLockedOut": "အသုံးပြုသူ ဝင်ရန် တားမြစ်ခံရသည်", "NotificationOptionUserLockedOut": "အသုံးပြုသူ ဝင်ရန် တားမြစ်ခံရသည်",
"NotificationOptionTaskFailed": "စီစဉ်ထားသော အလုပ်ပျက်ကွက်", "NotificationOptionTaskFailed": "စီစဉ်ထားသော အလုပ်ပျက်ကွက်",
"NotificationOptionServerRestartRequired": "ဆာဗာ ပြန်လည်စတင်ရန် လိုအပ်သည်", "NotificationOptionServerRestartRequired": "ဆာဗာ ပြန်လည်စတင်ရန် လိုအပ်သည်",
"NotificationOptionPluginUpdateInstalled": "ပလပ်အင် အပ်ဒိတ် ထည့်သွင်းပြီးပါပြီ", "NotificationOptionPluginUpdateInstalled": "ပလပ်အင် အပ်ဒိတ် ထည့်သွင်းပြီးပါပြီ",
"NotificationOptionPluginUninstalled": "ပလပ်အင်ကို ဖြုတ်လိုက်ပါပြီ", "NotificationOptionPluginUninstalled": "ပလပ်အင်ကို ဖြုတ်လိုက်ပါပြီ",
"NotificationOptionPluginInstalled": "ပလပ်အင် ထည့်သွင်းထားသည်", "NotificationOptionPluginInstalled": "ပလပ်အင် ထည့်သွင်းထားသည်",
"NotificationOptionPluginError": "ပလပ်အင် ချို့ယွင်းခြင်း", "NotificationOptionPluginError": "ပလပ်အင် ချို့ယွင်းခြင်း",
"NotificationOptionNewLibraryContent": "အသစ်များ ထပ်ထည့်ထားပါတယ်", "NotificationOptionNewLibraryContent": "အသစ်များ ထပ်ထည့်ထားပါတယ်",
"NotificationOptionInstallationFailed": "ထည့်သွင်းမှု မအောင်မြင်ပါ", "NotificationOptionInstallationFailed": "ထည့်သွင်းမှု မအောင်မြင်ပါ",
"NotificationOptionCameraImageUploaded": "ကင်မရာမှ ဓာတ်ပုံ အပ်လုဒ် ပြီးပါပြီ", "NotificationOptionCameraImageUploaded": "ကင်မရာမှ ဓာတ်ပုံ အပ်လုဒ် ပြီးပါပြီ",
"NotificationOptionAudioPlaybackStopped": "အသံဖိုင်ဖွင့်ခြင်း ရပ်သွားသည်", "NotificationOptionAudioPlaybackStopped": "အသံဖိုင်ဖွင့်ခြင်း ရပ်သွားသည်",
"NotificationOptionAudioPlayback": "အသံဖွင့်ခြင်း စတင်ပါပြီ", "NotificationOptionAudioPlayback": "အသံဖွင့်ခြင်း စတင်ပါပြီ",
"NotificationOptionApplicationUpdateInstalled": "အပလီကေးရှင်း အပ်ဒိတ်ကို ထည့်သွင်းထားသည်", "NotificationOptionApplicationUpdateInstalled": "အပလီကေးရှင်း အပ်ဒိတ်ကို ထည့်သွင်းထားသည်",
"NotificationOptionApplicationUpdateAvailable": "အပလီကေးရှင်း အပ်ဒိတ် ရနိုင်ပါပြီ", "NotificationOptionApplicationUpdateAvailable": "အပလီကေးရှင်း အပ်ဒိတ် ရနိုင်ပါပြီ",
"NewVersionIsAvailable": "Jellyfin Server ၏ ဗားရှင်းအသစ်ကို ဒေါင်းလုဒ်လုပ်နိုင်ပါပြီ။", "NewVersionIsAvailable": "Jellyfin Server ၏ ဗားရှင်းအသစ်ကို ဒေါင်းလုဒ်လုပ်နိုင်ပါပြီ။",
"NameSeasonUnknown": "ဇာတ်လမ်းတွဲ အပိုင်းမသိ", "NameSeasonUnknown": "ဇာတ်လမ်းတွဲ အပိုင်းမသိ",
"NameSeasonNumber": "ဇာတ်လမ်းတွဲ အပိုင်း {0}", "NameSeasonNumber": "ဇာတ်လမ်းတွဲ အပိုင်း {0}",
"NameInstallFailed": "{0} ထည့်သွင်းမှု မအောင်မြင်ပါ", "NameInstallFailed": "{0} ထည့်သွင်းမှု မအောင်မြင်ပါ",
"MusicVideos": "ဂီတဗီဒီယိုများ", "MusicVideos": "ဂီတဗီဒီယိုများ",
"Music": "တေးဂီတ", "Music": "တေးဂီတ",
"Movies": "ရုပ်ရှင်များ", "Movies": "ရုပ်ရှင်များ",
"MixedContent": "ရောနှောပါဝင်မှု", "MixedContent": "ရောနှောပါဝင်မှု",
"MessageServerConfigurationUpdated": "ဆာဗာဖွဲ့စည်းပုံကို အပ်ဒိတ်လုပ်ပြီးပါပြီ", "MessageServerConfigurationUpdated": "ဆာဗာဖွဲ့စည်းပုံကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"MessageNamedServerConfigurationUpdatedWithValue": "ဆာဗာဖွဲ့စည်းပုံကဏ္ဍ {0} ကို အပ်ဒိတ်လုပ်ပြီးပါပြီ", "MessageNamedServerConfigurationUpdatedWithValue": "ဆာဗာဖွဲ့စည်းပုံကဏ္ဍ {0} ကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"MessageApplicationUpdatedTo": "Jellyfin ဆာဗာကို {0} သို့ အပ်ဒိတ်လုပ်ထားသည်", "MessageApplicationUpdatedTo": "Jellyfin ဆာဗာကို {0} သို့ အပ်ဒိတ်လုပ်ထားသည်",
"MessageApplicationUpdated": "Jellyfin ဆာဗာကို အပ်ဒိတ်လုပ်ပြီးပါပြီ", "MessageApplicationUpdated": "Jellyfin ဆာဗာကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"Latest": "နောက်ဆုံး", "Latest": "နောက်ဆုံး",
"LabelRunningTimeValue": "ကြာချိန် - {0}", "LabelRunningTimeValue": "ကြာချိန် - {0}",
"LabelIpAddressValue": "IP လိပ်စာ- {0}", "LabelIpAddressValue": "IP လိပ်စာ- {0}",
"ItemRemovedWithName": "{0} ကို ဒစ်ဂျစ်တိုက်မှ ဖယ်ရှားခဲ့သည်", "ItemRemovedWithName": "{0} ကို ဒစ်ဂျစ်တိုက်မှ ဖယ်ရှားခဲ့သည်",
"ItemAddedWithName": "{0} ကို စာကြည့်တိုက်သို့ ထည့်ထားသည်", "ItemAddedWithName": "{0} ကို စာကြည့်တိုက်သို့ ထည့်ထားသည်",
"Inherit": "ဆက်ခံ၍ လုပ်ဆောင်သည်", "Inherit": "ဆက်ခံ၍ လုပ်ဆောင်သည်",
"HomeVideos": "ကိုယ်တိုင်ရိုက် ဗီဒီယိုများ", "HomeVideos": "ကိုယ်တိုင်ရိုက် ဗီဒီယိုများ",
"HeaderRecordingGroups": "အသံဖမ်းအဖွဲ့များ", "HeaderRecordingGroups": "အသံဖမ်းအဖွဲ့များ",
"HeaderNextUp": "နောက်ထပ်", "HeaderNextUp": "နောက်ထပ်",
@ -106,18 +106,18 @@
"HeaderFavoriteEpisodes": "အကြိုက်ဆုံး ဇာတ်လမ်းအပိုင်းများ", "HeaderFavoriteEpisodes": "အကြိုက်ဆုံး ဇာတ်လမ်းအပိုင်းများ",
"HeaderFavoriteArtists": "အကြိုက်ဆုံးအနုပညာရှင်များ", "HeaderFavoriteArtists": "အကြိုက်ဆုံးအနုပညာရှင်များ",
"HeaderFavoriteAlbums": "အကြိုက်ဆုံး အယ်လ်ဘမ်များ", "HeaderFavoriteAlbums": "အကြိုက်ဆုံး အယ်လ်ဘမ်များ",
"HeaderContinueWatching": "ဆက်လက်ကြည့်ရှုပါ", "HeaderContinueWatching": "ဆက်လက်ကြည့်ရှုပါ",
"HeaderAlbumArtists": "အယ်လ်ဘမ်အနုပညာရှင်များ", "HeaderAlbumArtists": "အယ်လ်ဘမ်အနုပညာရှင်များ",
"Genres": "အမျိုးအစားများ", "Genres": "အမျိုးအစားများ",
"Forced": "အတင်းအကြပ်", "Forced": "အတင်းအကြပ်",
"Folders": "ဖိုလ်ဒါများ", "Folders": "ဖိုလ်ဒါများ",
"Favorites": "အကြိုက်ဆုံးများ", "Favorites": "အကြိုက်ဆုံးများ",
"FailedLoginAttemptWithUserName": "{0} မှ အကောင့်ဝင်ရန် မအောင်မြင်ပါ", "FailedLoginAttemptWithUserName": "{0} မှ အကောင့်ဝင်ရန် မအောင်မြင်ပါ",
"DeviceOnlineWithName": "{0} ကို ချိတ်ဆက်ထားသည်", "DeviceOnlineWithName": "{0} ကို ချိတ်ဆက်ထားသည်",
"DeviceOfflineWithName": "{0} နှင့် အဆက်ပြတ်သွားပါပြီ", "DeviceOfflineWithName": "{0} နှင့် အဆက်ပြတ်သွားပါပြီ",
"ChapterNameValue": "အခန်း {0}", "ChapterNameValue": "အခန်း {0}",
"CameraImageUploadedFrom": "ကင်မရာပုံအသစ်ကို {0} မှ ထည့်သွင်းလိုက်သည်", "CameraImageUploadedFrom": "ကင်မရာပုံအသစ်ကို {0} မှ ထည့်သွင်းလိုက်သည်",
"AuthenticationSucceededWithUserName": "{0} စစ်မှန်ကြောင်း အောင်မြင်စွာ အတည်ပြုပြီးပါပြီ", "AuthenticationSucceededWithUserName": "{0} အောင်မြင်စွာ စစ်မှန်ကြောင်း အတည်ပြုပြီးပါပြီ",
"Application": "အပလီကေးရှင်း", "Application": "အပလီကေးရှင်း",
"AppDeviceValues": "အက်ပ်- {0}၊ စက်- {1}", "AppDeviceValues": "အက်ပ်- {0}၊ စက်- {1}",
"External": "ပြင်ပ" "External": "ပြင်ပ"

View File

@ -8,15 +8,15 @@
"CameraImageUploadedFrom": "Uma nova imagem de câmara foi enviada a partir de {0}", "CameraImageUploadedFrom": "Uma nova imagem de câmara foi enviada a partir de {0}",
"Channels": "Canais", "Channels": "Canais",
"ChapterNameValue": "Capítulo {0}", "ChapterNameValue": "Capítulo {0}",
"Collections": "Coleções", "Collections": "Colecções",
"DeviceOfflineWithName": "{0} desligou-se", "DeviceOfflineWithName": "{0} desligou-se",
"DeviceOnlineWithName": "{0} ligou-se", "DeviceOnlineWithName": "{0} ligou-se",
"FailedLoginAttemptWithUserName": "Tentativa de login falhada a partir de {0}", "FailedLoginAttemptWithUserName": "Tentativa de login falhada a partir de {0}",
"Favorites": "Favoritos", "Favorites": "Favoritos",
"Folders": "Pastas", "Folders": "Pastas",
"Genres": "Géneros", "Genres": "Géneros",
"HeaderAlbumArtists": "Artistas do Álbum", "HeaderAlbumArtists": "Artistas do álbum",
"HeaderContinueWatching": "Continuar a Ver", "HeaderContinueWatching": "Continuar a ver",
"HeaderFavoriteAlbums": "Álbuns Favoritos", "HeaderFavoriteAlbums": "Álbuns Favoritos",
"HeaderFavoriteArtists": "Artistas Favoritos", "HeaderFavoriteArtists": "Artistas Favoritos",
"HeaderFavoriteEpisodes": "Episódios Favoritos", "HeaderFavoriteEpisodes": "Episódios Favoritos",

View File

@ -1,5 +1,5 @@
{ {
"HeaderLiveTV": "TV Ao Vivo", "HeaderLiveTV": "TV Em Direto",
"Collections": "Coleções", "Collections": "Coleções",
"Books": "Livros", "Books": "Livros",
"Artists": "Artistas", "Artists": "Artistas",
@ -10,9 +10,9 @@
"HeaderFavoriteAlbums": "Álbuns Favoritos", "HeaderFavoriteAlbums": "Álbuns Favoritos",
"HeaderFavoriteEpisodes": "Episódios Favoritos", "HeaderFavoriteEpisodes": "Episódios Favoritos",
"HeaderFavoriteShows": "Séries Favoritas", "HeaderFavoriteShows": "Séries Favoritas",
"HeaderContinueWatching": "Continuar assistindo", "HeaderContinueWatching": "Continuar a ver",
"HeaderAlbumArtists": "Artistas do Álbum", "HeaderAlbumArtists": "Artistas do Álbum",
"Genres": "Gêneros", "Genres": "Géneros",
"Folders": "Diretórios", "Folders": "Diretórios",
"Favorites": "Favoritos", "Favorites": "Favoritos",
"Channels": "Canais", "Channels": "Canais",
@ -74,7 +74,7 @@
"ItemRemovedWithName": "{0} foi removido da biblioteca", "ItemRemovedWithName": "{0} foi removido da biblioteca",
"ItemAddedWithName": "{0} foi adicionado à biblioteca", "ItemAddedWithName": "{0} foi adicionado à biblioteca",
"Inherit": "Herdar", "Inherit": "Herdar",
"HomeVideos": "Vídeos principais", "HomeVideos": "Vídeos Caseiros",
"HeaderRecordingGroups": "Grupos de Gravação", "HeaderRecordingGroups": "Grupos de Gravação",
"ValueSpecialEpisodeName": "Episódio Especial - {0}", "ValueSpecialEpisodeName": "Episódio Especial - {0}",
"Sync": "Sincronização", "Sync": "Sincronização",
@ -83,14 +83,14 @@
"Playlists": "Listas de Reprodução", "Playlists": "Listas de Reprodução",
"Photos": "Fotografias", "Photos": "Fotografias",
"Movies": "Filmes", "Movies": "Filmes",
"FailedLoginAttemptWithUserName": "Tentativa falha de login a partir de {0}", "FailedLoginAttemptWithUserName": "Tentativa de início de sessão falhada a partir de {0}",
"DeviceOnlineWithName": "{0} está conectado", "DeviceOnlineWithName": "{0} está ligado",
"DeviceOfflineWithName": "{0} desconectou-se", "DeviceOfflineWithName": "{0} desligou-se",
"ChapterNameValue": "Capítulo {0}", "ChapterNameValue": "Capítulo {0}",
"CameraImageUploadedFrom": "Uma nova imagem da câmara foi enviada a partir de {0}", "CameraImageUploadedFrom": "Uma nova imagem da câmara foi enviada a partir de {0}",
"AuthenticationSucceededWithUserName": "{0} autenticado com sucesso", "AuthenticationSucceededWithUserName": "{0} autenticado com sucesso",
"Application": "Aplicativo", "Application": "Aplicação",
"AppDeviceValues": "Aplicativo {0}, Dispositivo: {1}", "AppDeviceValues": "Aplicação: {0}, Dispositivo: {1}",
"TaskCleanCache": "Limpar Diretório de Cache", "TaskCleanCache": "Limpar Diretório de Cache",
"TasksApplicationCategory": "Aplicativo", "TasksApplicationCategory": "Aplicativo",
"TasksLibraryCategory": "Biblioteca", "TasksLibraryCategory": "Biblioteca",

View File

@ -90,7 +90,7 @@
"UserStartedPlayingItemWithValues": "{0} predvaja {1} na {2}", "UserStartedPlayingItemWithValues": "{0} predvaja {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} je nehal predvajati {1} na {2}", "UserStoppedPlayingItemWithValues": "{0} je nehal predvajati {1} na {2}",
"ValueHasBeenAddedToLibrary": "{0} je bil dodan vaši knjižnici", "ValueHasBeenAddedToLibrary": "{0} je bil dodan vaši knjižnici",
"ValueSpecialEpisodeName": "Bonus - {0}", "ValueSpecialEpisodeName": "Posebna epizoda - {0}",
"VersionNumber": "Različica {0}", "VersionNumber": "Različica {0}",
"TaskDownloadMissingSubtitles": "Prenesi manjkajoče podnapise", "TaskDownloadMissingSubtitles": "Prenesi manjkajoče podnapise",
"TaskRefreshChannelsDescription": "Osveži podatke spletnih kanalov.", "TaskRefreshChannelsDescription": "Osveži podatke spletnih kanalov.",
@ -122,5 +122,6 @@
"TaskOptimizeDatabaseDescription": "Stisne bazo podatkov in uredi prazen prostor. Zagon tega opravila po iskanju predstavnosti ali drugih spremembah ki vplivajo na bazo podatkov lahko izboljša hitrost delovanja.", "TaskOptimizeDatabaseDescription": "Stisne bazo podatkov in uredi prazen prostor. Zagon tega opravila po iskanju predstavnosti ali drugih spremembah ki vplivajo na bazo podatkov lahko izboljša hitrost delovanja.",
"TaskOptimizeDatabase": "Optimiziraj bazo podatkov", "TaskOptimizeDatabase": "Optimiziraj bazo podatkov",
"TaskKeyframeExtractor": "Ekstraktor ključnih sličic", "TaskKeyframeExtractor": "Ekstraktor ključnih sličic",
"External": "Zunanje" "External": "Zunanji",
"TaskKeyframeExtractorDescription": "Iz video datoteke Izvleče ključne sličice, da ustvari bolj natančne sezname predvajanja HLS. Proces lahko traja dolgo časa."
} }

View File

@ -86,7 +86,7 @@
"Channels": "Канали", "Channels": "Канали",
"CameraImageUploadedFrom": "Нова фотографија је учитана са {0}", "CameraImageUploadedFrom": "Нова фотографија је учитана са {0}",
"Books": "Књиге", "Books": "Књиге",
"AuthenticationSucceededWithUserName": "{0} Успешна аутентикација", "AuthenticationSucceededWithUserName": "{0} Успешна аутентификација",
"Artists": "Извођачи", "Artists": "Извођачи",
"Application": "Апликација", "Application": "Апликација",
"AppDeviceValues": "Апликација: {0}, Уређај: {1}", "AppDeviceValues": "Апликација: {0}, Уређај: {1}",
@ -118,7 +118,7 @@
"Undefined": "Недефинисано", "Undefined": "Недефинисано",
"Forced": "Принудно", "Forced": "Принудно",
"Default": "Подразумевано", "Default": "Подразумевано",
"TaskOptimizeDatabase": "Оптимизуј датабазу", "TaskOptimizeDatabase": "Оптимизуј банку података",
"TaskOptimizeDatabaseDescription": "Сажима базу података и скраћује слободан простор. Покретање овог задатка након скенирања библиотеке или других промена које подразумевају измене базе података које могу побољшати перформансе.", "TaskOptimizeDatabaseDescription": "Сажима базу података и скраћује слободан простор. Покретање овог задатка након скенирања библиотеке или других промена које подразумевају измене базе података које могу побољшати перформансе.",
"External": "Спољно", "External": "Спољно",
"TaskKeyframeExtractorDescription": "Екстрактује кљулне сличице из видео датотека да би креирао више преицзну HLS плеј-листу. Овај задатак може да потраје дуже време.", "TaskKeyframeExtractorDescription": "Екстрактује кљулне сличице из видео датотека да би креирао више преицзну HLS плеј-листу. Овај задатак може да потраје дуже време.",

View File

@ -3,7 +3,122 @@
"Channels": "قانال", "Channels": "قانال",
"CameraImageUploadedFrom": "{0} ئورۇندىن يېڭى سۈرەت چىقىرىلدى", "CameraImageUploadedFrom": "{0} ئورۇندىن يېڭى سۈرەت چىقىرىلدى",
"Books": "كىتاب", "Books": "كىتاب",
"AuthenticationSucceededWithUserName": "تىزىملىتىش مۇۋەپپەقىيەتلىك بول", "AuthenticationSucceededWithUserName": "{0} تەستىقلاش مۇۋاپىقىيەتلىك بولدى",
"Artists": "سەنئەتكار", "Artists": "سەنئەتكار",
"Albums": "پىلاستىنكا" "Albums": "پىلاستىنكا",
"DeviceOnlineWithName": "{0} ئۇلاندى",
"DeviceOfflineWithName": "{0} ئۈزۈلدى",
"Collections": "توپلام",
"Application": "ئەپ",
"AppDeviceValues": "ئەپ: {0}، ئۈسكۈنە: {1}",
"HeaderLiveTV": "تور تېلېۋىزىيەسى",
"Default": "سۈكۈتتىكى",
"Folders": "ھۆججەت خالتىسى",
"Favorites": "ساقلىغۇچ",
"LabelRunningTimeValue": "ئىجرا بولغان ۋاقتى:{0}",
"HeaderRecordingGroups": "خاتىرلەش گۇرۇپىسى",
"Forced": "ئەڭ",
"TaskKeyframeExtractor": "ھالقىلىق رامكا ئاجراتقۇچ",
"TaskKeyframeExtractorDescription": "سىن ھۆججەتلىرىدىن رامكا ئاجرىتىپ، تېخىمۇ ئېنىق بولغان HLS قويۇلۇش تىزىملىكىنى قۇرۇلىدۇ. بۇ ۋەزىپە ئۇزۇن داۋام قىلىشى مۇمكىن.",
"TaskOptimizeDatabase": "سانداننى ئەلالاشتۇرۇش",
"TaskDownloadMissingSubtitlesDescription": "ئامىللار تەڭشىكىگە ئاساسەن توردىن كەم بولغان فىلىم خېتىنى ئىزدەش.",
"TaskDownloadMissingSubtitles": "كەم بولغان فىلىم خەتلىرىنى چۈشۈرۈش",
"TasksChannelsCategory": "ئىنتېرنېت قاناللىرى",
"TaskRefreshChannelsDescription": "ئىنتېرنېت قانىلى ئۇچۇرىنى يېڭىلاش.",
"TaskRefreshChannels": "قانالنى يېڭىلاش",
"TaskCleanTranscodeDescription": "بىر كۈندىن ئاشقان ئالماشتۇرۇش ھۆججەتلىرىنى ئۆچۈرۈش.",
"TaskCleanTranscode": "ئايلاندۇرۇش ھۆججەت قىسقۇچىنى تازىلاش",
"TaskUpdatePluginsDescription": "ئاپتوماتىك يېڭىلاشقا بېكىتىلگەن قىستۇرمىلارنىڭ يېڭىلانمىسىنى چۈشۈرۈش ۋە قاچىلاش.",
"TaskUpdatePlugins": "قىستۇرمىلارنى يېڭىلاش",
"TaskRefreshPeopleDescription": "مېدىيا ئامبىرىدىكى ئارتىس ۋە رېژىسسورلارنىڭ ئۇچۇرىنى يېڭىلاش.",
"TaskRefreshPeople": "ئابونتلارنى يېڭىلاش",
"TaskCleanLogsDescription": "{0} كۈندىن ئاشقان Log ھۆججىتىنى ئۆچۈرۈش.",
"TaskCleanLogs": "Log ھۆججەت قسقۇچىنى تازىلاش",
"TaskRefreshLibraryDescription": "مېدىيا ئامبىرىغا قوشۇلغان يېڭى ھۆججەتلەرنى ئىزدەش ۋە مېدىيا ئۇچۇرلىرىنى يېڭىلاش.",
"TaskRefreshLibrary": "مېدىيا ئامبىرىنى سىكاننېرلاش",
"TaskRefreshChapterImagesDescription": "ۋېدىئو بۆلەكلىرى ئۈچۈن كىچىك سۈرەت ياساش.",
"TaskRefreshChapterImages": "بۆلەكلەر رەسىملىرىنى چىقىرىۋېلىش",
"TaskCleanCacheDescription": "سىستېما ئىھتىياجى يوق بولغان ۋاقىتلىق ھۆججەتلەرنى ئۆچۈرۈش.",
"TaskCleanCache": "ۋاقىتلىق ھۆججەت قىسقۇچنى تازىلاش",
"TaskCleanActivityLogDescription": "ۋاقىت تەڭشىكىدىن بۇرۇنقى پائالىيەت خاتىرىسى خاتىرىسىنى ئۆچۈرۈش.",
"TaskCleanActivityLog": "پروگرامما خاتىرىسىنى تازىلاش",
"TasksApplicationCategory": "پروگرامما",
"TasksLibraryCategory": "مېدىيا ئامبىرى",
"TasksMaintenanceCategory": "ئاسراش",
"VersionNumber": "نەشرى {0}",
"ValueSpecialEpisodeName": "خاسلىق - {0}",
"ValueHasBeenAddedToLibrary": "{0} مېدىيا ئامبىرىڭىزغا قوشۇلدى",
"UserStoppedPlayingItemWithValues": "{0}،{1} نى {2} دە قويۇنشتىن توختىدى",
"UserStartedPlayingItemWithValues": "{0}،{1} نى {2} دە قويۇۋاتىدۇ",
"UserPolicyUpdatedWithName": "ئابونتلار سىياسىتى {0} غا يېڭىلاندى",
"UserPasswordChangedWithName": "ئابونت{0} ئۈچۈن پارول ئۆزگەرتىلدى",
"UserOfflineFromDevice": "{0} بىلەن {1} نىڭ ئالاقىسى ئۈزۈلدى",
"UserLockedOutWithName": "ئابونت {0} قۇلۇپلاندى",
"UserDownloadingItemWithValues": "{0} چۈشۈرۈۋاتىدۇ {1}",
"UserDeletedWithName": "{0} ئابونت ئۆچۈرۈلدى",
"UserCreatedWithName": "{0} ئابونت يېڭىدىن قوشۇلدى",
"User": "ئابونت",
"Undefined": "بېكىتىلمىگەن",
"TvShows": "تىياتىرلار",
"System": "سىستېما",
"Sync": "ماس قەدەمدەش",
"SubtitleDownloadFailureFromForItem": "{0} دىن {0} نىڭ فىلىم خېتىنى چۈشۈرگىلى بولمىدى",
"StartupEmbyServerIsLoading": "Jellyfin مۇلازىمىتېرى يۈكلىنىۋاتىدۇ. سەل تۇرۇپ قايتا سىناڭ.",
"Songs": "ناخشىلار",
"Shows": "پروگراممىلار",
"ServerNameNeedsToBeRestarted": "{0} قايتا قوزغىتىلىشى كېرەك",
"ScheduledTaskStartedWithName": "{0} باشلاندى",
"ScheduledTaskFailedWithName": "{0} مەغلۇپ بولدى",
"ProviderValue": "تەمىنلىگۈچى: {0}",
"PluginUpdatedWithName": "{0} يېڭىلاندى",
"PluginUninstalledWithName": "{0} ئۆچۈرۈلدى",
"PluginInstalledWithName": "{0} قاچىلاندى",
"Plugin": "قىستۇرما",
"Playlists": "قويۇش تىزىملىكى",
"Photos": "رەسىملەر",
"NotificationOptionVideoPlaybackStopped": "سىن قويۇلۇش توختىدى",
"NotificationOptionVideoPlayback": "سىن قويۇلدى",
"NotificationOptionUserLockedOut": "ئابونت قۇلۇپلاندى",
"NotificationOptionTaskFailed": "بەلگىلەنگەن ۋەزىپە مەغلۇپ بولدى",
"NotificationOptionServerRestartRequired": "مۇلازىمىتېر قايتا قوزغىتىلىشى كېرەك",
"NotificationOptionPluginUpdateInstalled": "قىستۇرما يېڭىلانمىسى قاچىلاندى",
"NotificationOptionPluginInstalled": "قىستۇرما قاچىلاندى",
"NotificationOptionPluginUninstalled": "قىستۇرما ئۆچۈرۈلدى",
"NotificationOptionPluginError": "قىستۇرما خاتالىقى",
"NotificationOptionNewLibraryContent": "يېڭى مەزمۇن قوشۇلدى",
"NotificationOptionInstallationFailed": "قاچىلاش مەغلۇب بولدى",
"NotificationOptionCameraImageUploaded": "كامىكامېرا سۈرىتى يوللاندى",
"NotificationOptionAudioPlayback": "ئاۋاز قويۇش باشلاندى",
"NotificationOptionAudioPlaybackStopped": "ئاۋاز قويۇش توختىدى",
"NotificationOptionApplicationUpdateInstalled": "ئەپ يېڭىلانمىسى ئورنىتىلدى",
"NotificationOptionApplicationUpdateAvailable": "ئەپنىڭ نەشرىنى يېڭىلىغىلى بولۇدۇ",
"NewVersionIsAvailable": "Jellyfin Server نىڭ يېڭى نۇسخىسىنى چۈشۈرگىلى بولىدۇ.",
"NameSeasonUnknown": "نامەمۇم بۆلۈم",
"NameSeasonNumber": "{0}-بۆلۈم",
"NameInstallFailed": "{0} قاچىلاش مەغلۇپ بولدى",
"MusicVideos": "سىنلىق مۇزىكا",
"Music": "مۇزىكا",
"Movies": "فىلىملەر",
"MixedContent": "ئارىلاشما مەزمۇن",
"MessageNamedServerConfigurationUpdatedWithValue": "مۇلازىمىتېر تەڭشىكىنىڭ {0} قىسمى يېڭىلىنىپ بولدى",
"MessageServerConfigurationUpdated": "مۇلازىمىتېر يېڭىلىنىپ بولدى",
"MessageApplicationUpdated": "Jellyfin مۇلازىمىتېرى يېڭىلاندى",
"MessageApplicationUpdatedTo": "Jellyfin مۇلازىمىتېر نەشرى {0} گە يېڭىلاندى",
"Latest": "ئەڭ يېڭى",
"LabelIpAddressValue": "{0}: IP ئادرىسى",
"ItemRemovedWithName": "{0} ئامباردىن چىقىرىلدى",
"ItemAddedWithName": "{0} ئامبارغا قوشۇلدى",
"Inherit": "داۋاملاشتۇرۇش",
"HomeVideos": "ئائىلە سىنلىرى",
"HeaderNextUp": "كېيىنكىسى",
"HeaderFavoriteSongs": "ئەڭ ياقتۇرىدىغان ناخشىلار",
"HeaderFavoriteShows": "ئەڭ ياقتۇرىدىغان پروگراممىلار",
"HeaderFavoriteEpisodes": "ئەڭ ياقتۇرىدىغان تىياتېرلار",
"HeaderFavoriteArtists": "ئەڭ ياقتۇرىدىغان سەنئەتكارلار",
"HeaderFavoriteAlbums": "ياقتۇرىدىغان پىلاستىنكىلار",
"HeaderContinueWatching": "داۋاملىق كۆرۈش",
"HeaderAlbumArtists": "پىلاستىنكا سەنئەتكارلىرى",
"Genres": "ئۇسلۇبلار",
"FailedLoginAttemptWithUserName": "{0} كىرىش ئوڭۇشلۇق بولمىدى",
"External": "سىرتقى"
} }

View File

@ -120,5 +120,8 @@
"Default": "預設", "Default": "預設",
"TaskOptimizeDatabaseDescription": "壓縮數據庫並截斷可用空間。在掃描媒體庫或執行其他數據庫的修改後運行此任務可能會提高性能。", "TaskOptimizeDatabaseDescription": "壓縮數據庫並截斷可用空間。在掃描媒體庫或執行其他數據庫的修改後運行此任務可能會提高性能。",
"TaskOptimizeDatabase": "最佳化數據庫", "TaskOptimizeDatabase": "最佳化數據庫",
"TaskCleanActivityLogDescription": "刪除早於設定時間的日誌記錄。" "TaskCleanActivityLogDescription": "刪除早於設定時間的日誌記錄。",
"TaskKeyframeExtractorDescription": "提取關鍵格以創建更準確的HLS播放列表。次指示可能用時很長。",
"TaskKeyframeExtractor": "關鍵幀提取器",
"External": "外部"
} }

View File

@ -0,0 +1,10 @@
FI-S,1
FI-T,1
FI-7,4
FI-12,5
FI-16,8
FI-18,9
FI-K7,4
FI-K12,5
FI-K16,8
FI-K18,9
1 FI-S 1
2 FI-T 1
3 FI-7 4
4 FI-12 5
5 FI-16 8
6 FI-18 9
7 FI-K7 4
8 FI-K12 5
9 FI-K16 8
10 FI-K18 9

View File

@ -0,0 +1,6 @@
NO-A,1
NO-6,3
NO-9,4
NO-12,5
NO-15,8
NO-18,9
1 NO-A 1
2 NO-6 3
3 NO-9 4
4 NO-12 5
5 NO-15 8
6 NO-18 9

View File

@ -0,0 +1,5 @@
SE-Btl,1
SE-Barntillåten,1
SE-7,3
SE-11,5
SE-15,8
1 SE-Btl 1
2 SE-Barntillåten 1
3 SE-7 3
4 SE-11 5
5 SE-15 8

View File

@ -63,10 +63,7 @@ namespace Emby.Server.Implementations.Net
/// <inheritdoc /> /// <inheritdoc />
public ISocket CreateUdpMulticastSocket(IPAddress ipAddress, int multicastTimeToLive, int localPort) public ISocket CreateUdpMulticastSocket(IPAddress ipAddress, int multicastTimeToLive, int localPort)
{ {
if (ipAddress == null) ArgumentNullException.ThrowIfNull(ipAddress);
{
throw new ArgumentNullException(nameof(ipAddress));
}
if (multicastTimeToLive <= 0) if (multicastTimeToLive <= 0)
{ {

View File

@ -35,10 +35,7 @@ namespace Emby.Server.Implementations.Net
public UdpSocket(Socket socket, int localPort, IPAddress ip) public UdpSocket(Socket socket, int localPort, IPAddress ip)
{ {
if (socket == null) ArgumentNullException.ThrowIfNull(socket);
{
throw new ArgumentNullException(nameof(socket));
}
_socket = socket; _socket = socket;
_localPort = localPort; _localPort = localPort;
@ -51,10 +48,7 @@ namespace Emby.Server.Implementations.Net
public UdpSocket(Socket socket, IPEndPoint endPoint) public UdpSocket(Socket socket, IPEndPoint endPoint)
{ {
if (socket == null) ArgumentNullException.ThrowIfNull(socket);
{
throw new ArgumentNullException(nameof(socket));
}
_socket = socket; _socket = socket;
_socket.Connect(endPoint); _socket.Connect(endPoint);
@ -96,7 +90,7 @@ namespace Emby.Server.Implementations.Net
} }
else else
{ {
tcs.TrySetException(new Exception("SocketError: " + e.SocketError)); tcs.TrySetException(new SocketException((int)e.SocketError));
} }
} }
} }
@ -114,7 +108,7 @@ namespace Emby.Server.Implementations.Net
} }
else else
{ {
tcs.TrySetException(new Exception("SocketError: " + e.SocketError)); tcs.TrySetException(new SocketException((int)e.SocketError));
} }
} }
} }

View File

@ -234,10 +234,7 @@ namespace Emby.Server.Implementations.Plugins
/// <returns>Outcome of the operation.</returns> /// <returns>Outcome of the operation.</returns>
public bool RemovePlugin(LocalPlugin plugin) public bool RemovePlugin(LocalPlugin plugin)
{ {
if (plugin == null) ArgumentNullException.ThrowIfNull(plugin);
{
throw new ArgumentNullException(nameof(plugin));
}
if (DeletePlugin(plugin)) if (DeletePlugin(plugin))
{ {
@ -288,10 +285,7 @@ namespace Emby.Server.Implementations.Plugins
/// <param name="plugin">The <see cref="LocalPlugin"/> of the plug to disable.</param> /// <param name="plugin">The <see cref="LocalPlugin"/> of the plug to disable.</param>
public void EnablePlugin(LocalPlugin plugin) public void EnablePlugin(LocalPlugin plugin)
{ {
if (plugin == null) ArgumentNullException.ThrowIfNull(plugin);
{
throw new ArgumentNullException(nameof(plugin));
}
if (ChangePluginState(plugin, PluginStatus.Active)) if (ChangePluginState(plugin, PluginStatus.Active))
{ {
@ -306,10 +300,7 @@ namespace Emby.Server.Implementations.Plugins
/// <param name="plugin">The <see cref="LocalPlugin"/> of the plug to disable.</param> /// <param name="plugin">The <see cref="LocalPlugin"/> of the plug to disable.</param>
public void DisablePlugin(LocalPlugin plugin) public void DisablePlugin(LocalPlugin plugin)
{ {
if (plugin == null) ArgumentNullException.ThrowIfNull(plugin);
{
throw new ArgumentNullException(nameof(plugin));
}
// Update the manifest on disk // Update the manifest on disk
if (ChangePluginState(plugin, PluginStatus.Disabled)) if (ChangePluginState(plugin, PluginStatus.Disabled))
@ -326,10 +317,7 @@ namespace Emby.Server.Implementations.Plugins
public void FailPlugin(Assembly assembly) public void FailPlugin(Assembly assembly)
{ {
// Only save if disabled. // Only save if disabled.
if (assembly == null) ArgumentNullException.ThrowIfNull(assembly);
{
throw new ArgumentNullException(nameof(assembly));
}
var plugin = _plugins.FirstOrDefault(p => p.DllFiles.Contains(assembly.Location)); var plugin = _plugins.FirstOrDefault(p => p.DllFiles.Contains(assembly.Location));
if (plugin == null) if (plugin == null)

View File

@ -92,25 +92,13 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// </exception> /// </exception>
public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, ILogger logger) public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, ILogger logger)
{ {
if (scheduledTask == null) ArgumentNullException.ThrowIfNull(scheduledTask);
{
throw new ArgumentNullException(nameof(scheduledTask));
}
if (applicationPaths == null) ArgumentNullException.ThrowIfNull(applicationPaths);
{
throw new ArgumentNullException(nameof(applicationPaths));
}
if (taskManager == null) ArgumentNullException.ThrowIfNull(taskManager);
{
throw new ArgumentNullException(nameof(taskManager));
}
if (logger == null) ArgumentNullException.ThrowIfNull(logger);
{
throw new ArgumentNullException(nameof(logger));
}
ScheduledTask = scheduledTask; ScheduledTask = scheduledTask;
_applicationPaths = applicationPaths; _applicationPaths = applicationPaths;
@ -249,10 +237,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
get => _triggers; get => _triggers;
set set
{ {
if (value == null) ArgumentNullException.ThrowIfNull(value);
{
throw new ArgumentNullException(nameof(value));
}
// Cleanup current triggers // Cleanup current triggers
if (_triggers != null) if (_triggers != null)
@ -281,10 +266,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
set set
{ {
if (value == null) ArgumentNullException.ThrowIfNull(value);
{
throw new ArgumentNullException(nameof(value));
}
// This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly // This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly
var triggerList = value.Where(i => i != null).ToArray(); var triggerList = value.Where(i => i != null).ToArray();

View File

@ -665,10 +665,7 @@ namespace Emby.Server.Implementations.Session
{ {
CheckDisposed(); CheckDisposed();
if (info == null) ArgumentNullException.ThrowIfNull(info);
{
throw new ArgumentNullException(nameof(info));
}
var session = GetSession(info.SessionId); var session = GetSession(info.SessionId);
@ -762,10 +759,7 @@ namespace Emby.Server.Implementations.Session
{ {
CheckDisposed(); CheckDisposed();
if (info == null) ArgumentNullException.ThrowIfNull(info);
{
throw new ArgumentNullException(nameof(info));
}
var session = GetSession(info.SessionId); var session = GetSession(info.SessionId);
@ -897,10 +891,7 @@ namespace Emby.Server.Implementations.Session
{ {
CheckDisposed(); CheckDisposed();
if (info == null) ArgumentNullException.ThrowIfNull(info);
{
throw new ArgumentNullException(nameof(info));
}
if (info.PositionTicks.HasValue && info.PositionTicks.Value < 0) if (info.PositionTicks.HasValue && info.PositionTicks.Value < 0)
{ {
@ -1242,7 +1233,7 @@ namespace Emby.Server.Implementations.Session
if (item == null) if (item == null)
{ {
_logger.LogError("A non-existant item Id {0} was passed into TranslateItemForPlayback", id); _logger.LogError("A non-existent item Id {0} was passed into TranslateItemForPlayback", id);
return Array.Empty<BaseItem>(); return Array.Empty<BaseItem>();
} }
@ -1341,15 +1332,9 @@ namespace Emby.Server.Implementations.Session
private static void AssertCanControl(SessionInfo session, SessionInfo controllingSession) private static void AssertCanControl(SessionInfo session, SessionInfo controllingSession)
{ {
if (session == null) ArgumentNullException.ThrowIfNull(session);
{
throw new ArgumentNullException(nameof(session));
}
if (controllingSession == null) ArgumentNullException.ThrowIfNull(controllingSession);
{
throw new ArgumentNullException(nameof(controllingSession));
}
} }
/// <summary> /// <summary>
@ -1688,10 +1673,7 @@ namespace Emby.Server.Implementations.Session
/// </summary> /// </summary>
private BaseItemDto GetItemInfo(BaseItem item, MediaSourceInfo mediaSource) private BaseItemDto GetItemInfo(BaseItem item, MediaSourceInfo mediaSource)
{ {
if (item == null) ArgumentNullException.ThrowIfNull(item);
{
throw new ArgumentNullException(nameof(item));
}
var dtoOptions = _itemInfoDtoOptions; var dtoOptions = _itemInfoDtoOptions;
@ -1802,10 +1784,7 @@ namespace Emby.Server.Implementations.Session
/// <inheritdoc /> /// <inheritdoc />
public Task<SessionInfo> GetSessionByAuthenticationToken(Device info, string deviceId, string remoteEndpoint, string appVersion) public Task<SessionInfo> GetSessionByAuthenticationToken(Device info, string deviceId, string remoteEndpoint, string appVersion)
{ {
if (info == null) ArgumentNullException.ThrowIfNull(info);
{
throw new ArgumentNullException(nameof(info));
}
var user = info.UserId.Equals(default) var user = info.UserId.Equals(default)
? null ? null

View File

@ -6,7 +6,7 @@ using System.Linq;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.Extensions; using Jellyfin.Api.Extensions;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.Session
private const float ForceKeepAliveFactor = 0.75f; private const float ForceKeepAliveFactor = 0.75f;
/// <summary> /// <summary>
/// Lock used for accesing the KeepAlive cancellation token. /// Lock used for accessing the KeepAlive cancellation token.
/// </summary> /// </summary>
private readonly object _keepAliveLock = new object(); private readonly object _keepAliveLock = new object();
@ -54,7 +54,6 @@ namespace Emby.Server.Implementations.Session
private readonly ISessionManager _sessionManager; private readonly ISessionManager _sessionManager;
private readonly ILogger<SessionWebSocketListener> _logger; private readonly ILogger<SessionWebSocketListener> _logger;
private readonly ILoggerFactory _loggerFactory; private readonly ILoggerFactory _loggerFactory;
private readonly IAuthorizationContext _authorizationContext;
/// <summary> /// <summary>
/// The KeepAlive cancellation token. /// The KeepAlive cancellation token.
@ -67,17 +66,14 @@ namespace Emby.Server.Implementations.Session
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
/// <param name="sessionManager">The session manager.</param> /// <param name="sessionManager">The session manager.</param>
/// <param name="loggerFactory">The logger factory.</param> /// <param name="loggerFactory">The logger factory.</param>
/// <param name="authorizationContext">The authorization context.</param>
public SessionWebSocketListener( public SessionWebSocketListener(
ILogger<SessionWebSocketListener> logger, ILogger<SessionWebSocketListener> logger,
ISessionManager sessionManager, ISessionManager sessionManager,
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory)
IAuthorizationContext authorizationContext)
{ {
_logger = logger; _logger = logger;
_sessionManager = sessionManager; _sessionManager = sessionManager;
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory;
_authorizationContext = authorizationContext;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -111,21 +107,18 @@ namespace Emby.Server.Implementations.Session
private async Task<SessionInfo> GetSession(HttpContext httpContext, string remoteEndpoint) private async Task<SessionInfo> GetSession(HttpContext httpContext, string remoteEndpoint)
{ {
var authorizationInfo = await _authorizationContext.GetAuthorizationInfo(httpContext) if (!httpContext.User.Identity?.IsAuthenticated ?? false)
.ConfigureAwait(false);
if (!authorizationInfo.IsAuthenticated)
{ {
return null; return null;
} }
var deviceId = authorizationInfo.DeviceId; var deviceId = httpContext.User.GetDeviceId();
if (httpContext.Request.Query.TryGetValue("deviceId", out var queryDeviceId)) if (httpContext.Request.Query.TryGetValue("deviceId", out var queryDeviceId))
{ {
deviceId = queryDeviceId; deviceId = queryDeviceId;
} }
return await _sessionManager.GetSessionByAuthenticationToken(authorizationInfo.Token, deviceId, remoteEndpoint) return await _sessionManager.GetSessionByAuthenticationToken(httpContext.User.GetToken(), deviceId, remoteEndpoint)
.ConfigureAwait(false); .ConfigureAwait(false);
} }

View File

@ -24,15 +24,9 @@ namespace Emby.Server.Implementations.Sorting
/// <returns>System.Int32.</returns> /// <returns>System.Int32.</returns>
public int Compare(BaseItem? x, BaseItem? y) public int Compare(BaseItem? x, BaseItem? y)
{ {
if (x == null) ArgumentNullException.ThrowIfNull(x);
{
throw new ArgumentNullException(nameof(x));
}
if (y == null) ArgumentNullException.ThrowIfNull(y);
{
throw new ArgumentNullException(nameof(y));
}
var episode1 = x as Episode; var episode1 = x as Episode;
var episode2 = y as Episode; var episode2 = y as Episode;

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