aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.dockerignore2
-rw-r--r--.gitmodules3
-rw-r--r--CONTRIBUTORS.md3
-rw-r--r--Dockerfile.arm9
-rw-r--r--Dockerfile.arm6433
-rw-r--r--Emby.Photos/Emby.Photos.csproj5
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs14
-rw-r--r--Emby.Server.Implementations/Diagnostics/CommonProcess.cs18
-rw-r--r--Jellyfin.Server/Jellyfin.Server.csproj5
-rw-r--r--Jellyfin.Server/Program.cs10
-rw-r--r--Jellyfin.Server/SocketSharp/RequestMono.cs168
-rw-r--r--Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs10
-rw-r--r--Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs64
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs6
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs20
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs2
-rw-r--r--MediaBrowser.Api/Playback/UniversalAudioService.cs26
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs9
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs7
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs4
-rw-r--r--MediaBrowser.Model/Dlna/AudioOptions.cs20
-rw-r--r--MediaBrowser.Model/Dlna/ConditionProcessor.cs24
-rw-r--r--MediaBrowser.Model/Dlna/DeviceProfile.cs12
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs458
m---------MediaBrowser.WebDashboard/jellyfin-web0
-rw-r--r--MediaBrowser.sln6
-rw-r--r--Mono.Nat/Upnp/Searchers/UpnpSearcher.cs6
-rw-r--r--SharedVersion.cs4
-rw-r--r--SocketHttpListener/HttpBase.cs18
-rw-r--r--SocketHttpListener/HttpResponse.cs4
-rw-r--r--SocketHttpListener/Net/HttpConnection.cs9
-rw-r--r--SocketHttpListener/WebSocket.cs9
-rwxr-xr-xbuild23
-rwxr-xr-xbump_version22
-rwxr-xr-xdeployment/common.build.sh3
-rw-r--r--deployment/debian-package-x64/pkg-src/changelog83
-rwxr-xr-xdeployment/fedora-package-x64/clean.sh13
-rwxr-xr-xdeployment/fedora-package-x64/package.sh19
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.spec83
-rw-r--r--jellyfin.ruleset13
42 files changed, 778 insertions, 473 deletions
diff --git a/.dockerignore b/.dockerignore
index 54b0aa3a7..45e543525 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,6 +1,8 @@
.git
.dockerignore
Dockerfile
+Dockerfile.arm
+Dockerfile.arm64
CONTRIBUTORS.md
README.md
deployment/*/dist
diff --git a/.gitmodules b/.gitmodules
index 7aeb94dfc..c10f5905c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "ThirdParty/taglib-sharp"]
- path = ThirdParty/taglib-sharp
- url = https://github.com/mono/taglib-sharp.git
[submodule "MediaBrowser.WebDashboard/jellyfin-web"]
path = MediaBrowser.WebDashboard/jellyfin-web
url = https://github.com/jellyfin/jellyfin-web.git
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 17df49f30..8ae6c81a8 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -14,7 +14,8 @@
- [grafixeyehero](https://github.com/grafixeyehero)
- [cvium](https://github.com/cvium)
- [wtayl0r](https://github.com/wtayl0r)
-
+ - [TtheCreator](https://github.com/Tthecreator)
+
# Emby Contributors
- [LukePulverenti](https://github.com/LukePulverenti)
diff --git a/Dockerfile.arm b/Dockerfile.arm
index a0b3d0e1d..239fdd1c1 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -1,18 +1,21 @@
ARG DOTNET_VERSION=3.0
-FROM microsoft/dotnet:${DOTNET_VERSION}-sdk as builder
+
+FROM microsoft/dotnet:${DOTNET_VERSION}-sdk-stretch-arm32v7 as builder
WORKDIR /repo
COPY . .
#TODO Remove or update the sed line when we update dotnet version.
RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \
&& find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \; \
- && dotnet clean \
+ && dotnet clean -maxcpucount:1 \
&& dotnet publish \
+ -maxcpucount:1 \
--configuration release \
--output /jellyfin \
Jellyfin.Server
-FROM microsoft/dotnet:${DOTNET_VERSION}-runtime
+
+FROM microsoft/dotnet:${DOTNET_VERSION}-runtime-stretch-slim-arm32v7
COPY --from=builder /jellyfin /jellyfin
EXPOSE 8096
RUN apt-get update \
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
new file mode 100644
index 000000000..6d7aa2118
--- /dev/null
+++ b/Dockerfile.arm64
@@ -0,0 +1,33 @@
+# Requires binfm_misc registration for aarch64
+# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
+ARG DOTNET_VERSION=3.0
+
+
+FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
+FROM alpine as qemu_extract
+COPY --from=qemu /usr/bin qemu_user_static.tgz
+RUN tar -xzvf qemu_user_static.tgz
+
+
+FROM microsoft/dotnet:${DOTNET_VERSION}-sdk-stretch-arm64v8 as builder
+COPY --from=qemu_extract qemu-* /usr/bin
+WORKDIR /repo
+COPY . .
+#TODO Remove or update the sed line when we update dotnet version.
+RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \
+ && find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \; \
+ && dotnet clean \
+ && dotnet publish \
+ --configuration release \
+ --output /jellyfin \
+ Jellyfin.Server
+
+
+FROM microsoft/dotnet:${DOTNET_VERSION}-runtime-stretch-slim-arm64v8
+COPY --from=qemu_extract qemu-* /usr/bin
+COPY --from=builder /jellyfin /jellyfin
+EXPOSE 8096
+RUN apt-get update \
+ && apt-get install -y ffmpeg
+VOLUME /config /media
+ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
diff --git a/Emby.Photos/Emby.Photos.csproj b/Emby.Photos/Emby.Photos.csproj
index e6b445202..c9830abc5 100644
--- a/Emby.Photos/Emby.Photos.csproj
+++ b/Emby.Photos/Emby.Photos.csproj
@@ -3,13 +3,16 @@
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
- <ProjectReference Include="..\ThirdParty\taglib-sharp\src\taglib-sharp.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs" />
</ItemGroup>
+ <ItemGroup>
+ <PackageReference Include="TagLibSharp" Version="2.2.0-beta" />
+ </ItemGroup>
+
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 492adef6a..21294f96f 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -4712,9 +4712,21 @@ namespace Emby.Server.Implementations.Data
continue;
}
- var paramName = "@HasAnyProviderId" + index;
+ // TODO this seems to be an idea for a better schema where ProviderIds are their own table
+ // buut this is not implemented
//hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
+
+ // TODO this is a really BAD way to do it since the pair:
+ // Tmdb, 1234 matches Tmdb=1234 but also Tmdb=1234567
+ // and maybe even NotTmdb=1234.
+
+ // this is a placeholder for this specific pair to correlate it in the bigger query
+ var paramName = "@HasAnyProviderId" + index;
+
+ // this is a search for the placeholder
hasProviderIds.Add("ProviderIds like " + paramName + "");
+
+ // this replaces the placeholder with a value, here: %key=val%
if (statement != null)
{
statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
diff --git a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
index d8a798c46..55539eafc 100644
--- a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
+++ b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
@@ -105,26 +105,22 @@ namespace Emby.Server.Implementations.Diagnostics
{
return _process.WaitForExit(timeMs);
}
-
+
public Task<bool> WaitForExitAsync(int timeMs)
{
- //if (_process.WaitForExit(100))
- //{
- // return Task.FromResult(true);
- //}
+ //Note: For this function to work correctly, the option EnableRisingEvents needs to be set to true.
+
+ if (HasExited)
+ {
+ return Task.FromResult(true);
+ }
- //timeMs -= 100;
timeMs = Math.Max(0, timeMs);
var tcs = new TaskCompletionSource<bool>();
var cancellationToken = new CancellationTokenSource(timeMs).Token;
- if (HasExited)
- {
- return Task.FromResult(true);
- }
-
_process.Exited += (sender, args) => tcs.TrySetResult(true);
cancellationToken.Register(() => tcs.TrySetResult(HasExited));
diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj
index 897d93339..0622d94b8 100644
--- a/Jellyfin.Server/Jellyfin.Server.csproj
+++ b/Jellyfin.Server/Jellyfin.Server.csproj
@@ -27,6 +27,11 @@
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
</ItemGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 0510548b5..c196a3f23 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -224,7 +224,7 @@ namespace Jellyfin.Server
.GetManifestResourceStream("Jellyfin.Server.Resources.Configuration.logging.json"))
using (Stream fstr = File.Open(configPath, FileMode.CreateNew))
{
- await rscstr.CopyToAsync(fstr);
+ await rscstr.CopyToAsync(fstr).ConfigureAwait(false);
}
}
var configuration = new ConfigurationBuilder()
@@ -334,11 +334,9 @@ namespace Jellyfin.Server
}
else
{
- commandLineArgsString = string.Join(" ",
- Environment.GetCommandLineArgs()
- .Skip(1)
- .Select(NormalizeCommandLineArgument)
- );
+ commandLineArgsString = string.Join(
+ " ",
+ Environment.GetCommandLineArgs().Skip(1).Select(NormalizeCommandLineArgument));
}
_logger.LogInformation("Executable: {0}", module);
diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs
index 45cb323d2..017690062 100644
--- a/Jellyfin.Server/SocketSharp/RequestMono.cs
+++ b/Jellyfin.Server/SocketSharp/RequestMono.cs
@@ -15,19 +15,27 @@ namespace Jellyfin.SocketSharp
{
int ap = header.IndexOf(attr);
if (ap == -1)
+ {
return null;
+ }
ap += attr.Length;
if (ap >= header.Length)
+ {
return null;
+ }
char ending = header[ap];
if (ending != '"')
+ {
ending = ' ';
+ }
int end = header.IndexOf(ending, ap + 1);
if (end == -1)
+ {
return ending == '"' ? null : header.Substring(ap);
+ }
return header.Substring(ap + 1, end - ap - 1);
}
@@ -36,7 +44,9 @@ namespace Jellyfin.SocketSharp
{
string boundary = GetParameter(ContentType, "; boundary=");
if (boundary == null)
+ {
return;
+ }
using (var requestStream = InputStream)
{
@@ -124,7 +134,9 @@ namespace Jellyfin.SocketSharp
{
string v = "\"" + value + "\"";
if (v.Length > 20)
+ {
v = v.Substring(0, 16) + "...\"";
+ }
string msg = string.Format("A potentially dangerous Request.{0} value was " +
"detected from the client ({1}={2}).", name, key, v);
@@ -135,21 +147,23 @@ namespace Jellyfin.SocketSharp
static void ValidateNameValueCollection(string name, QueryParamCollection coll)
{
if (coll == null)
+ {
return;
+ }
foreach (var pair in coll)
{
var key = pair.Name;
var val = pair.Value;
if (val != null && val.Length > 0 && IsInvalidString(val))
+ {
ThrowValidationException(name, key, val);
+ }
}
}
internal static bool IsInvalidString(string val)
- {
- return IsInvalidString(val, out var validationFailureIndex);
- }
+ => IsInvalidString(val, out var validationFailureIndex);
internal static bool IsInvalidString(string val, out int validationFailureIndex)
{
@@ -157,7 +171,9 @@ namespace Jellyfin.SocketSharp
int len = val.Length;
if (len < 2)
+ {
return false;
+ }
char current = val[0];
for (int idx = 1; idx < len; idx++)
@@ -195,10 +211,15 @@ namespace Jellyfin.SocketSharp
bool IsContentType(string ct, bool starts_with)
{
- if (ct == null || ContentType == null) return false;
+ if (ct == null || ContentType == null)
+ {
+ return false;
+ }
if (starts_with)
+ {
return StrUtils.StartsWith(ContentType, ct, true);
+ }
return string.Equals(ContentType, ct, StringComparison.OrdinalIgnoreCase);
}
@@ -231,7 +252,9 @@ namespace Jellyfin.SocketSharp
break;
}
else
+ {
value.Append((char)c);
+ }
}
if (c == -1)
{
@@ -240,22 +263,26 @@ namespace Jellyfin.SocketSharp
}
}
else if (c == '&')
+ {
AddRawKeyValue(form, key, value);
+ }
else
+ {
key.Append((char)c);
+ }
}
if (c == -1)
+ {
AddRawKeyValue(form, key, value);
+ }
}
}
}
}
- void AddRawKeyValue(WebROCollection form, StringBuilder key, StringBuilder value)
+ static void AddRawKeyValue(WebROCollection form, StringBuilder key, StringBuilder value)
{
- string decodedKey = WebUtility.UrlDecode(key.ToString());
- form.Add(decodedKey,
- WebUtility.UrlDecode(value.ToString()));
+ form.Add(WebUtility.UrlDecode(key.ToString()), WebUtility.UrlDecode(value.ToString()));
key.Length = 0;
value.Length = 0;
@@ -271,7 +298,9 @@ namespace Jellyfin.SocketSharp
foreach (var pair in this)
{
if (result.Length > 0)
+ {
result.Append('&');
+ }
var key = pair.Name;
if (key != null && key.Length > 0)
@@ -314,33 +343,52 @@ namespace Jellyfin.SocketSharp
public override int Read(byte[] buffer, int dest_offset, int count)
{
if (buffer == null)
+ {
throw new ArgumentNullException(nameof(buffer));
+ }
if (dest_offset < 0)
+ {
throw new ArgumentOutOfRangeException(nameof(dest_offset), "< 0");
+ }
if (count < 0)
+ {
throw new ArgumentOutOfRangeException(nameof(count), "< 0");
+ }
int len = buffer.Length;
if (dest_offset > len)
+ {
throw new ArgumentException("destination offset is beyond array size");
+ }
+
// reordered to avoid possible integer overflow
if (dest_offset > len - count)
+ {
throw new ArgumentException("Reading would overrun buffer");
+ }
if (count > end - position)
+ {
count = (int)(end - position);
+ }
if (count <= 0)
+ {
return 0;
+ }
s.Position = position;
int result = s.Read(buffer, dest_offset, count);
if (result > 0)
+ {
position += result;
+ }
else
+ {
position = end;
+ }
return result;
}
@@ -348,14 +396,20 @@ namespace Jellyfin.SocketSharp
public override int ReadByte()
{
if (position >= end)
+ {
return -1;
+ }
s.Position = position;
int result = s.ReadByte();
if (result < 0)
+ {
position = end;
+ }
else
+ {
position++;
+ }
return result;
}
@@ -380,7 +434,9 @@ namespace Jellyfin.SocketSharp
long virt = real - offset;
if (virt < 0 || virt > Length)
+ {
throw new ArgumentException();
+ }
position = s.Seek(real, SeekOrigin.Begin);
return position;
@@ -410,7 +466,9 @@ namespace Jellyfin.SocketSharp
set
{
if (value > Length)
- throw new ArgumentOutOfRangeException();
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
position = Seek(value, SeekOrigin.Begin);
}
@@ -438,7 +496,7 @@ namespace Jellyfin.SocketSharp
public static readonly CultureInfo InvariantCulture = CultureInfo.InvariantCulture;
}
- internal sealed class StrUtils
+ internal static class StrUtils
{
public static bool StartsWith(string str1, string str2, bool ignore_case)
{
@@ -455,11 +513,15 @@ namespace Jellyfin.SocketSharp
{
int l2 = str2.Length;
if (l2 == 0)
+ {
return true;
+ }
int l1 = str1.Length;
if (l2 > l1)
+ {
return false;
+ }
var comparison = ignore_case ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
return str1.IndexOf(str2, comparison) == str1.Length - str2.Length - 1;
@@ -493,7 +555,7 @@ namespace Jellyfin.SocketSharp
Encoding encoding;
StringBuilder sb;
- const byte HYPHEN = (byte)'-', LF = (byte)'\n', CR = (byte)'\r';
+ const byte LF = (byte)'\n', CR = (byte)'\r';
// See RFC 2046
// In the case of multipart entities, in which one or more different
@@ -520,7 +582,7 @@ namespace Jellyfin.SocketSharp
sb = new StringBuilder();
}
- string ReadLine()
+ private string ReadLine()
{
// CRLF or LF are ok as line endings.
bool got_cr = false;
@@ -543,58 +605,86 @@ namespace Jellyfin.SocketSharp
}
if (got_cr)
+ {
sb.Length--;
+ }
return sb.ToString();
}
- static string GetContentDispositionAttribute(string l, string name)
+ private static string GetContentDispositionAttribute(string l, string name)
{
int idx = l.IndexOf(name + "=\"");
if (idx < 0)
+ {
return null;
+ }
+
int begin = idx + name.Length + "=\"".Length;
int end = l.IndexOf('"', begin);
if (end < 0)
+ {
return null;
+ }
+
if (begin == end)
- return "";
+ {
+ return string.Empty;
+ }
+
return l.Substring(begin, end - begin);
}
- string GetContentDispositionAttributeWithEncoding(string l, string name)
+ private string GetContentDispositionAttributeWithEncoding(string l, string name)
{
int idx = l.IndexOf(name + "=\"");
if (idx < 0)
+ {
return null;
+ }
+
int begin = idx + name.Length + "=\"".Length;
int end = l.IndexOf('"', begin);
if (end < 0)
+ {
return null;
+ }
+
if (begin == end)
- return "";
+ {
+ return string.Empty;
+ }
string temp = l.Substring(begin, end - begin);
byte[] source = new byte[temp.Length];
for (int i = temp.Length - 1; i >= 0; i--)
+ {
source[i] = (byte)temp[i];
+ }
return encoding.GetString(source, 0, source.Length);
}
- bool ReadBoundary()
+ private bool ReadBoundary()
{
try
{
string line = ReadLine();
- while (line == "")
+ while (line == string.Empty)
+ {
line = ReadLine();
+ }
+
if (line[0] != '-' || line[1] != '-')
+ {
return false;
+ }
if (!StrUtils.EndsWith(line, boundary, false))
+ {
return true;
+ }
}
catch
{
@@ -603,25 +693,31 @@ namespace Jellyfin.SocketSharp
return false;
}
- string ReadHeaders()
+ private string ReadHeaders()
{
string s = ReadLine();
- if (s == "")
+ if (s.Length == 0)
+ {
return null;
+ }
return s;
}
- bool CompareBytes(byte[] orig, byte[] other)
+ private static bool CompareBytes(byte[] orig, byte[] other)
{
for (int i = orig.Length - 1; i >= 0; i--)
+ {
if (orig[i] != other[i])
+ {
return false;
+ }
+ }
return true;
}
- long MoveToNextBoundary()
+ private long MoveToNextBoundary()
{
long retval = 0;
bool got_cr = false;
@@ -631,13 +727,18 @@ namespace Jellyfin.SocketSharp
while (true)
{
if (c == -1)
+ {
return -1;
+ }
if (state == 0 && c == LF)
{
retval = data.Position - 1;
if (got_cr)
+ {
retval--;
+ }
+
state = 1;
c = data.ReadByte();
}
@@ -650,7 +751,9 @@ namespace Jellyfin.SocketSharp
{
c = data.ReadByte();
if (c == -1)
+ {
return -1;
+ }
if (c != '-')
{
@@ -662,7 +765,9 @@ namespace Jellyfin.SocketSharp
int nread = data.Read(buffer, 0, buffer.Length);
int bl = buffer.Length;
if (nread != bl)
+ {
return -1;
+ }
if (!CompareBytes(boundary_bytes, buffer))
{
@@ -673,6 +778,7 @@ namespace Jellyfin.SocketSharp
data.Position++;
got_cr = false;
}
+
c = data.ReadByte();
continue;
}
@@ -690,12 +796,16 @@ namespace Jellyfin.SocketSharp
data.Position++;
got_cr = false;
}
+
c = data.ReadByte();
continue;
}
data.Position = retval + 2;
if (got_cr)
+ {
data.Position++;
+ }
+
break;
}
else
@@ -711,7 +821,9 @@ namespace Jellyfin.SocketSharp
public Element ReadNextElement()
{
if (at_eof || ReadBoundary())
+ {
return null;
+ }
var elem = new Element();
string header;
@@ -734,19 +846,27 @@ namespace Jellyfin.SocketSharp
elem.Start = start;
long pos = MoveToNextBoundary();
if (pos == -1)
+ {
return null;
+ }
elem.Length = pos - start;
return elem;
}
- static string StripPath(string path)
+ private static string StripPath(string path)
{
if (path == null || path.Length == 0)
+ {
return path;
+ }
- if (path.IndexOf(":\\") != 1 && !path.StartsWith("\\\\"))
+ if (path.IndexOf(":\\", StringComparison.Ordinal) != 1
+ && !path.StartsWith("\\\\", StringComparison.Ordinal))
+ {
return path;
+ }
+
return path.Substring(path.LastIndexOf('\\') + 1);
}
}
diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs
index ef75644d7..c7f9f01b5 100644
--- a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs
+++ b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs
@@ -83,15 +83,15 @@ namespace Jellyfin.SocketSharp
private void ProcessContext(HttpListenerContext context)
{
- //InitTask(context, _disposeCancellationToken);
- Task.Run(() => InitTask(context, _disposeCancellationToken));
+ var _ = Task.Run(async () => await InitTask(context, _disposeCancellationToken));
}
- private void LogRequest(ILogger logger, HttpListenerRequest request)
+ private static void LogRequest(ILogger logger, HttpListenerRequest request)
{
var url = request.Url.ToString();
- logger.LogInformation("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty);
+ logger.LogInformation("{0} {1}. UserAgent: {2}",
+ request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty);
}
private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken)
@@ -196,7 +196,7 @@ namespace Jellyfin.SocketSharp
{
try
{
- ctx.Response.StatusCode = 200;
+ ctx.Response.StatusCode = statusCode;
ctx.Response.Close();
}
catch (ObjectDisposedException)
diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs
index e38468388..97550e686 100644
--- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs
+++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs
@@ -242,7 +242,6 @@ namespace Jellyfin.SocketSharp
return request.ContentType.StartsWith(contentType, StringComparison.OrdinalIgnoreCase);
}
- public const string Xml = "application/xml";
private static string GetQueryStringContentType(IRequest httpReq)
{
var format = httpReq.QueryString["format"];
@@ -250,22 +249,40 @@ namespace Jellyfin.SocketSharp
{
const int formatMaxLength = 4;
var pi = httpReq.PathInfo;
- if (pi == null || pi.Length <= formatMaxLength) return null;
- if (pi[0] == '/') pi = pi.Substring(1);
+ if (pi == null || pi.Length <= formatMaxLength)
+ {
+ return null;
+ }
+ if (pi[0] == '/')
+ {
+ pi = pi.Substring(1);
+ }
format = LeftPart(pi, '/');
- if (format.Length > formatMaxLength) return null;
+ if (format.Length > formatMaxLength)
+ {
+ return null;
+ }
}
format = LeftPart(format, '.').ToLower();
- if (format.Contains("json")) return "application/json";
- if (format.Contains("xml")) return Xml;
+ if (format.Contains("json", StringComparison.OrdinalIgnoreCase))
+ {
+ return "application/json";
+ }
+ if (format.Contains("xml", StringComparison.OrdinalIgnoreCase))
+ {
+ return "application/xml";
+ }
return null;
}
public static string LeftPart(string strVal, char needle)
{
- if (strVal == null) return null;
+ if (strVal == null)
+ {
+ return null;
+ }
var pos = strVal.IndexOf(needle);
return pos == -1
? strVal
@@ -283,14 +300,14 @@ namespace Jellyfin.SocketSharp
{
var mode = HandlerFactoryPath;
- var pos = request.RawUrl.IndexOf("?");
+ var pos = request.RawUrl.IndexOf("?", StringComparison.Ordinal);
if (pos != -1)
{
var path = request.RawUrl.Substring(0, pos);
this.pathInfo = GetPathInfo(
path,
mode,
- mode ?? "");
+ mode ?? string.Empty);
}
else
{
@@ -307,18 +324,27 @@ namespace Jellyfin.SocketSharp
private static string GetPathInfo(string fullPath, string mode, string appPath)
{
var pathInfo = ResolvePathInfoFromMappedPath(fullPath, mode);
- if (!string.IsNullOrEmpty(pathInfo)) return pathInfo;
+ if (!string.IsNullOrEmpty(pathInfo))
+ {
+ return pathInfo;
+ }
//Wildcard mode relies on this to work out the handlerPath
pathInfo = ResolvePathInfoFromMappedPath(fullPath, appPath);
- if (!string.IsNullOrEmpty(pathInfo)) return pathInfo;
+ if (!string.IsNullOrEmpty(pathInfo))
+ {
+ return pathInfo;
+ }
return fullPath;
}
private static string ResolvePathInfoFromMappedPath(string fullPath, string mappedPathRoot)
{
- if (mappedPathRoot == null) return null;
+ if (mappedPathRoot == null)
+ {
+ return null;
+ }
var sbPathInfo = new StringBuilder();
var fullPathParts = fullPath.Split('/');
@@ -345,7 +371,10 @@ namespace Jellyfin.SocketSharp
}
}
}
- if (!pathRootFound) return null;
+ if (!pathRootFound)
+ {
+ return null;
+ }
var path = sbPathInfo.ToString();
return path.Length > 1 ? path.TrimEnd('/') : "/";
@@ -400,7 +429,10 @@ namespace Jellyfin.SocketSharp
public static Encoding GetEncoding(string contentTypeHeader)
{
var param = GetParameter(contentTypeHeader, "charset=");
- if (param == null) return null;
+ if (param == null)
+ {
+ return null;
+ }
try
{
return Encoding.GetEncoding(param);
@@ -423,7 +455,9 @@ namespace Jellyfin.SocketSharp
if (httpFiles == null)
{
if (files == null)
- return httpFiles = new IHttpFile[0];
+ {
+ return httpFiles = Array.Empty<IHttpFile>();
+ }
httpFiles = new IHttpFile[files.Count];
var i = 0;
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index a488576da..b3099e17e 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -936,10 +936,10 @@ namespace MediaBrowser.Api.Playback.Hls
var timeDeltaParam = string.Empty;
- if (isEncoding && state.TargetFramerate > 0)
+ if (isEncoding && startNumber > 0)
{
- float startTime = 1 / (state.TargetFramerate.Value * 2);
- timeDeltaParam = string.Format("-segment_time_delta {0}", Math.Round(startTime, 3));
+ var startTime = state.SegmentLength * startNumber;
+ timeDeltaParam = string.Format("-segment_time_delta -{0}", startTime);
}
var segmentFormat = GetSegmentFileExtension(state.Request).TrimStart('.');
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index 1c7be52f3..ab3994a63 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -74,8 +74,19 @@ namespace MediaBrowser.Api.Playback
private readonly IUserManager _userManager;
private readonly IJsonSerializer _json;
private readonly IAuthorizationContext _authContext;
-
- public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager, IMediaEncoder mediaEncoder, IUserManager userManager, IJsonSerializer json, IAuthorizationContext authContext)
+ private readonly ILogger _logger;
+
+ public MediaInfoService(
+ IMediaSourceManager mediaSourceManager,
+ IDeviceManager deviceManager,
+ ILibraryManager libraryManager,
+ IServerConfigurationManager config,
+ INetworkManager networkManager,
+ IMediaEncoder mediaEncoder,
+ IUserManager userManager,
+ IJsonSerializer json,
+ IAuthorizationContext authContext,
+ ILoggerFactory loggerFactory)
{
_mediaSourceManager = mediaSourceManager;
_deviceManager = deviceManager;
@@ -86,6 +97,7 @@ namespace MediaBrowser.Api.Playback
_userManager = userManager;
_json = json;
_authContext = authContext;
+ _logger = loggerFactory.CreateLogger(nameof(MediaInfoService));
}
public object Get(GetBitrateTestBytes request)
@@ -165,7 +177,7 @@ namespace MediaBrowser.Api.Playback
var profile = request.DeviceProfile;
- //Logger.Info("GetPostedPlaybackInfo profile: {0}", _json.SerializeToString(profile));
+ //Logger.LogInformation("GetPostedPlaybackInfo profile: {profile}", _json.SerializeToString(profile));
if (profile == null)
{
@@ -262,7 +274,7 @@ namespace MediaBrowser.Api.Playback
catch (Exception ex)
{
mediaSources = new List<MediaSourceInfo>();
- // TODO Log exception
+ _logger.LogError(ex, "Could not find media sources for item id {id}", id);
// TODO PlaybackException ??
//result.ErrorCode = ex.ErrorCode;
}
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index 96dc4ab4c..8d4b0cb3d 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -167,7 +167,7 @@ namespace MediaBrowser.Api.Playback
public DeviceProfile DeviceProfile { get; set; }
public TranscodingJob TranscodingJob;
- public void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
+ public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float framerate, double? percentComplete, long bytesTranscoded, int? bitRate)
{
ApiEntryPoint.Instance.ReportTranscodingProgress(TranscodingJob, this, transcodingPosition, framerate, percentComplete, bytesTranscoded, bitRate);
}
diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs
index 1faa32ba9..1aa77792c 100644
--- a/MediaBrowser.Api/Playback/UniversalAudioService.cs
+++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs
@@ -19,6 +19,7 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
+using Microsoft.Extensions.Logging;
namespace MediaBrowser.Api.Playback
{
@@ -75,7 +76,24 @@ namespace MediaBrowser.Api.Playback
[Authenticated]
public class UniversalAudioService : BaseApiService
{
- public UniversalAudioService(IServerConfigurationManager serverConfigurationManager, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, IDeviceManager deviceManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, INetworkManager networkManager, IEnvironmentInfo environmentInfo)
+ public UniversalAudioService(
+ IServerConfigurationManager serverConfigurationManager,
+ IUserManager userManager,
+ ILibraryManager libraryManager,
+ IIsoManager isoManager,
+ IMediaEncoder mediaEncoder,
+ IFileSystem fileSystem,
+ IDlnaManager dlnaManager,
+ IDeviceManager deviceManager,
+ ISubtitleEncoder subtitleEncoder,
+ IMediaSourceManager mediaSourceManager,
+ IZipClient zipClient,
+ IJsonSerializer jsonSerializer,
+ IAuthorizationContext authorizationContext,
+ IImageProcessor imageProcessor,
+ INetworkManager networkManager,
+ IEnvironmentInfo environmentInfo,
+ ILoggerFactory loggerFactory)
{
ServerConfigurationManager = serverConfigurationManager;
UserManager = userManager;
@@ -93,6 +111,8 @@ namespace MediaBrowser.Api.Playback
ImageProcessor = imageProcessor;
NetworkManager = networkManager;
EnvironmentInfo = environmentInfo;
+ _loggerFactory = loggerFactory;
+ _logger = loggerFactory.CreateLogger(nameof(UniversalAudioService));
}
protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
@@ -111,6 +131,8 @@ namespace MediaBrowser.Api.Playback
protected IImageProcessor ImageProcessor { get; private set; }
protected INetworkManager NetworkManager { get; private set; }
protected IEnvironmentInfo EnvironmentInfo { get; private set; }
+ private ILoggerFactory _loggerFactory;
+ private ILogger _logger;
public Task<object> Get(GetUniversalAudioStream request)
{
@@ -221,7 +243,7 @@ namespace MediaBrowser.Api.Playback
AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId;
- var mediaInfoService = new MediaInfoService(MediaSourceManager, DeviceManager, LibraryManager, ServerConfigurationManager, NetworkManager, MediaEncoder, UserManager, JsonSerializer, AuthorizationContext)
+ var mediaInfoService = new MediaInfoService(MediaSourceManager, DeviceManager, LibraryManager, ServerConfigurationManager, NetworkManager, MediaEncoder, UserManager, JsonSerializer, AuthorizationContext, _loggerFactory)
{
Request = Request
};
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index 0552fbbd8..08aa540a5 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -156,14 +156,19 @@ namespace MediaBrowser.Api.Subtitles
throw new ArgumentException("HLS Subtitles are not supported for this media.");
}
+ var segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks;
+ if (segmentLengthTicks <= 0)
+ {
+ throw new ArgumentException("segmentLength was not given, or it was given incorrectly. (It should be bigger than 0)");
+ }
+
builder.AppendLine("#EXTM3U");
builder.AppendLine("#EXT-X-TARGETDURATION:" + request.SegmentLength.ToString(CultureInfo.InvariantCulture));
builder.AppendLine("#EXT-X-VERSION:3");
builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
builder.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
- long positionTicks = 0;
- var segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks;
+ long positionTicks = 0;
var accessToken = _authContext.GetAuthorizationInfo(Request).Token;
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index a3e05f0d2..5b2939b75 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
/// <value>The tracks.</value>
[IgnoreDataMember]
- public IEnumerable<BaseItem> Tracks => GetRecursiveChildren(i => i is Audio);
+ public IEnumerable<Audio> Tracks => GetRecursiveChildren(i => i is Audio).Cast<Audio>();
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
{
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index d313848fe..5534576f1 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -357,7 +357,7 @@ namespace MediaBrowser.Controller.Entities
{
var list = new List<Tuple<StringBuilder, bool>>();
- int thisMarker = 0, thisNumericChunk = 0;
+ int thisMarker = 0;
while (thisMarker < s1.Length)
{
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 2103e0045..dab96509c 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -644,12 +644,9 @@ namespace MediaBrowser.Controller.Entities
return PostFilterAndSort(items, query, true);
}
- if (!(this is UserRootFolder) && !(this is AggregateFolder))
+ if (!(this is UserRootFolder) && !(this is AggregateFolder) && query.ParentId == Guid.Empty)
{
- if (!query.ParentId.Equals(Guid.Empty))
- {
- query.Parent = this;
- }
+ query.Parent = this;
}
if (RequiresPostFiltering2(query))
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 59a624433..2f9eb98ea 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -437,7 +437,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
UseShellExecute = false,
FileName = _mediaEncoder.EncoderPath,
Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
-
+ EnableRaisingEvents = true,
IsHidden = true,
ErrorDialog = false
});
@@ -574,7 +574,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
CreateNoWindow = true,
UseShellExecute = false,
-
+ EnableRaisingEvents = true,
FileName = _mediaEncoder.EncoderPath,
Arguments = processArgs,
IsHidden = true,
diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs
index 33e2982e9..6dfe8093e 100644
--- a/MediaBrowser.Model/Dlna/AudioOptions.cs
+++ b/MediaBrowser.Model/Dlna/AudioOptions.cs
@@ -66,21 +66,21 @@ namespace MediaBrowser.Model.Dlna
return MaxBitrate;
}
- if (Profile != null)
+ if (Profile == null)
{
- if (Context == EncodingContext.Static)
+ return null;
+ }
+
+ if (Context == EncodingContext.Static)
+ {
+ if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
{
- if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
- {
- return Profile.MaxStaticMusicBitrate;
- }
- return Profile.MaxStaticBitrate;
+ return Profile.MaxStaticMusicBitrate;
}
-
- return Profile.MaxStreamingBitrate;
+ return Profile.MaxStaticBitrate;
}
- return null;
+ return Profile.MaxStreamingBitrate;
}
}
}
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
index dc0c5f139..3629d1547 100644
--- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs
+++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
@@ -5,9 +5,10 @@ using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Model.Dlna
{
- public class ConditionProcessor
+ public static class ConditionProcessor
{
- public bool IsVideoConditionSatisfied(ProfileCondition condition,
+ public static bool IsVideoConditionSatisfied(
+ ProfileCondition condition,
int? width,
int? height,
int? videoBitDepth,
@@ -64,7 +65,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- public bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height)
+ public static bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height)
{
switch (condition.Property)
{
@@ -77,7 +78,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- public bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
+ public static bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
{
switch (condition.Property)
{
@@ -94,7 +95,8 @@ namespace MediaBrowser.Model.Dlna
}
}
- public bool IsVideoAudioConditionSatisfied(ProfileCondition condition,
+ public static bool IsVideoAudioConditionSatisfied(
+ ProfileCondition condition,
int? audioChannels,
int? audioBitrate,
int? audioSampleRate,
@@ -121,7 +123,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- private bool IsConditionSatisfied(ProfileCondition condition, int? currentValue)
+ private static bool IsConditionSatisfied(ProfileCondition condition, int? currentValue)
{
if (!currentValue.HasValue)
{
@@ -150,7 +152,7 @@ namespace MediaBrowser.Model.Dlna
return false;
}
- private bool IsConditionSatisfied(ProfileCondition condition, string currentValue)
+ private static bool IsConditionSatisfied(ProfileCondition condition, string currentValue)
{
if (string.IsNullOrEmpty(currentValue))
{
@@ -175,7 +177,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- private bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue)
+ private static bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue)
{
if (!currentValue.HasValue)
{
@@ -199,7 +201,7 @@ namespace MediaBrowser.Model.Dlna
return false;
}
- private bool IsConditionSatisfied(ProfileCondition condition, float currentValue)
+ private static bool IsConditionSatisfied(ProfileCondition condition, float currentValue)
{
if (currentValue <= 0)
{
@@ -227,7 +229,7 @@ namespace MediaBrowser.Model.Dlna
return false;
}
- private bool IsConditionSatisfied(ProfileCondition condition, double? currentValue)
+ private static bool IsConditionSatisfied(ProfileCondition condition, double? currentValue)
{
if (!currentValue.HasValue)
{
@@ -255,7 +257,7 @@ namespace MediaBrowser.Model.Dlna
return false;
}
- private bool IsConditionSatisfied(ProfileCondition condition, TransportStreamTimestamp? timestamp)
+ private static bool IsConditionSatisfied(ProfileCondition condition, TransportStreamTimestamp? timestamp)
{
if (!timestamp.HasValue)
{
diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs
index 6894f45ed..8d8fe9eb5 100644
--- a/MediaBrowser.Model/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs
@@ -188,12 +188,10 @@ namespace MediaBrowser.Model.Dlna
continue;
}
- var conditionProcessor = new ConditionProcessor();
-
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
- if (!conditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate, audioBitDepth))
+ if (!ConditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate, audioBitDepth))
{
anyOff = true;
break;
@@ -235,12 +233,10 @@ namespace MediaBrowser.Model.Dlna
continue;
}
- var conditionProcessor = new ConditionProcessor();
-
var anyOff = false;
foreach (var c in i.Conditions)
{
- if (!conditionProcessor.IsImageConditionSatisfied(GetModelProfileCondition(c), width, height))
+ if (!ConditionProcessor.IsImageConditionSatisfied(GetModelProfileCondition(c), width, height))
{
anyOff = true;
break;
@@ -301,12 +297,10 @@ namespace MediaBrowser.Model.Dlna
continue;
}
- var conditionProcessor = new ConditionProcessor();
-
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!ConditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
anyOff = true;
break;
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index ec05e2eb7..6c6e09ab1 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -93,19 +93,10 @@ namespace MediaBrowser.Model.Dlna
return GetOptimalStream(streams, options.GetMaxBitrate(false) ?? 0);
}
- private StreamInfo GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
- {
- var sorted = SortMediaSources(streams, maxBitrate);
-
- foreach (StreamInfo stream in sorted)
- {
- return stream;
- }
+ private static StreamInfo GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
+ => SortMediaSources(streams, maxBitrate).FirstOrDefault();
- return null;
- }
-
- private StreamInfo[] SortMediaSources(List<StreamInfo> streams, long maxBitrate)
+ private static IOrderedEnumerable<StreamInfo> SortMediaSources(List<StreamInfo> streams, long maxBitrate)
{
return streams.OrderBy(i =>
{
@@ -151,25 +142,17 @@ namespace MediaBrowser.Model.Dlna
return 0;
- }).ThenBy(streams.IndexOf).ToArray();
+ }).ThenBy(streams.IndexOf);
}
- private TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
+ private static TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
{
switch (condition.Property)
{
case ProfileConditionValue.AudioBitrate:
- if (condition.Condition == ProfileConditionType.LessThanEqual)
- {
- return TranscodeReason.AudioBitrateNotSupported;
- }
return TranscodeReason.AudioBitrateNotSupported;
case ProfileConditionValue.AudioChannels:
- if (condition.Condition == ProfileConditionType.LessThanEqual)
- {
- return TranscodeReason.AudioChannelsNotSupported;
- }
return TranscodeReason.AudioChannelsNotSupported;
case ProfileConditionValue.AudioProfile:
@@ -246,7 +229,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, string unused1, DeviceProfile profile, DlnaProfileType type)
+ public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, string _, DeviceProfile profile, DlnaProfileType type)
{
if (string.IsNullOrEmpty(inputContainer))
{
@@ -266,12 +249,10 @@ namespace MediaBrowser.Model.Dlna
{
foreach (var directPlayProfile in profile.DirectPlayProfiles)
{
- if (directPlayProfile.Type == type)
+ if (directPlayProfile.Type == type
+ && directPlayProfile.SupportsContainer(format))
{
- if (directPlayProfile.SupportsContainer(format))
- {
- return format;
- }
+ return format;
}
}
}
@@ -282,9 +263,7 @@ namespace MediaBrowser.Model.Dlna
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
{
- var transcodeReasons = new List<TranscodeReason>();
-
- var playlistItem = new StreamInfo
+ StreamInfo playlistItem = new StreamInfo
{
ItemId = options.ItemId,
MediaType = DlnaProfileType.Audio,
@@ -313,18 +292,16 @@ namespace MediaBrowser.Model.Dlna
var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
var directPlayMethods = directPlayInfo.Item1;
- transcodeReasons.AddRange(directPlayInfo.Item2);
-
- var conditionProcessor = new ConditionProcessor();
+ var transcodeReasons = directPlayInfo.Item2.ToList();
- int? inputAudioChannels = audioStream == null ? null : audioStream.Channels;
- int? inputAudioBitrate = audioStream == null ? null : audioStream.BitDepth;
- int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
- int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
+ int? inputAudioChannels = audioStream?.Channels;
+ int? inputAudioBitrate = audioStream?.BitDepth;
+ int? inputAudioSampleRate = audioStream?.SampleRate;
+ int? inputAudioBitDepth = audioStream.BitDepth;
- if (directPlayMethods.Count > 0)
+ if (directPlayMethods.Count() > 0)
{
- string audioCodec = audioStream == null ? null : audioStream.Codec;
+ string audioCodec = audioStream?.Codec;
// Make sure audio codec profiles are satisfied
var conditions = new List<ProfileCondition>();
@@ -335,7 +312,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
{
- if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
+ if (!ConditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
{
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
applyConditions = false;
@@ -345,10 +322,7 @@ namespace MediaBrowser.Model.Dlna
if (applyConditions)
{
- foreach (ProfileCondition c in i.Conditions)
- {
- conditions.Add(c);
- }
+ conditions.AddRange(i.Conditions);
}
}
}
@@ -356,7 +330,7 @@ namespace MediaBrowser.Model.Dlna
bool all = true;
foreach (ProfileCondition c in conditions)
{
- if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
+ if (!ConditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
{
LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
var transcodeReason = GetTranscodeReasonForFailedCondition(c);
@@ -385,13 +359,12 @@ namespace MediaBrowser.Model.Dlna
TranscodingProfile transcodingProfile = null;
foreach (var i in options.Profile.TranscodingProfiles)
{
- if (i.Type == playlistItem.MediaType && i.Context == options.Context)
+ if (i.Type == playlistItem.MediaType
+ && i.Context == options.Context
+ && _transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container))
{
- if (_transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container))
- {
- transcodingProfile = i;
- break;
- }
+ transcodingProfile = i;
+ break;
}
}
@@ -421,7 +394,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
foreach (var applyCondition in i.ApplyConditions)
{
- if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
+ if (!ConditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
{
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
applyConditions = false;
@@ -463,7 +436,7 @@ namespace MediaBrowser.Model.Dlna
return playlistItem;
}
- private long? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options, bool isAudio)
+ private static long? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options, bool isAudio)
{
if (item.Protocol == MediaProtocol.File)
{
@@ -473,65 +446,56 @@ namespace MediaBrowser.Model.Dlna
return options.GetMaxBitrate(isAudio);
}
- private Tuple<List<PlayMethod>, List<TranscodeReason>> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
+ private (IEnumerable<PlayMethod>, IEnumerable<TranscodeReason>) GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
{
- var transcodeReasons = new List<TranscodeReason>();
+ DirectPlayProfile directPlayProfile = options.Profile.DirectPlayProfiles
+ .FirstOrDefault(x => x.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(x, item, audioStream));
- DirectPlayProfile directPlayProfile = null;
- foreach (var i in options.Profile.DirectPlayProfiles)
+ if (directPlayProfile == null)
{
- if (i.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(i, item, audioStream))
- {
- directPlayProfile = i;
- break;
- }
+ _logger.LogInformation("Profile: {0}, No direct play profiles found for Path: {1}",
+ options.Profile.Name ?? "Unknown Profile",
+ item.Path ?? "Unknown path");
+
+ return (Enumerable.Empty<PlayMethod>(), GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
}
var playMethods = new List<PlayMethod>();
+ var transcodeReasons = new List<TranscodeReason>();
- if (directPlayProfile != null)
+ // While options takes the network and other factors into account. Only applies to direct stream
+ if (item.SupportsDirectStream)
{
- // While options takes the network and other factors into account. Only applies to direct stream
- if (item.SupportsDirectStream)
+ if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
{
- if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
- {
- if (options.EnableDirectStream)
- {
- playMethods.Add(PlayMethod.DirectStream);
- }
- }
- else
+ if (options.EnableDirectStream)
{
- transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
+ playMethods.Add(PlayMethod.DirectStream);
}
}
+ else
+ {
+ transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
+ }
+ }
- // The profile describes what the device supports
- // If device requirements are satisfied then allow both direct stream and direct play
- if (item.SupportsDirectPlay)
+ // The profile describes what the device supports
+ // If device requirements are satisfied then allow both direct stream and direct play
+ if (item.SupportsDirectPlay)
+ {
+ if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, PlayMethod.DirectPlay))
{
- if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, PlayMethod.DirectPlay))
- {
- if (options.EnableDirectPlay)
- {
- playMethods.Add(PlayMethod.DirectPlay);
- }
- }
- else
+ if (options.EnableDirectPlay)
{
- transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
+ playMethods.Add(PlayMethod.DirectPlay);
}
}
+ else
+ {
+ transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
+ }
}
- else
- {
- transcodeReasons.InsertRange(0, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
- _logger.LogInformation("Profile: {0}, No direct play profiles found for Path: {1}",
- options.Profile.Name ?? "Unknown Profile",
- item.Path ?? "Unknown path");
- }
if (playMethods.Count > 0)
{
@@ -542,41 +506,25 @@ namespace MediaBrowser.Model.Dlna
transcodeReasons = transcodeReasons.Distinct().ToList();
}
- return new Tuple<List<PlayMethod>, List<TranscodeReason>>(playMethods, transcodeReasons);
+ return (playMethods, transcodeReasons);
}
- private List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
+ private static List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
{
- var list = new List<TranscodeReason>();
var containerSupported = false;
var audioSupported = false;
var videoSupported = false;
foreach (var profile in directPlayProfiles)
{
- audioSupported = false;
- videoSupported = false;
-
// Check container type
if (profile.SupportsContainer(item.Container))
{
containerSupported = true;
- if (videoStream != null)
- {
- if (profile.SupportsVideoCodec(videoStream.Codec))
- {
- videoSupported = true;
- }
- }
+ videoSupported = videoStream != null && profile.SupportsVideoCodec(videoStream.Codec);
- if (audioStream != null)
- {
- if (profile.SupportsAudioCodec(audioStream.Codec))
- {
- audioSupported = true;
- }
- }
+ audioSupported = audioStream != null && profile.SupportsAudioCodec(audioStream.Codec);
if (videoSupported && audioSupported)
{
@@ -585,6 +533,7 @@ namespace MediaBrowser.Model.Dlna
}
}
+ var list = new List<TranscodeReason>();
if (!containerSupported)
{
list.Add(TranscodeReason.ContainerNotSupported);
@@ -603,18 +552,17 @@ namespace MediaBrowser.Model.Dlna
return list;
}
- private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
+ private static int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
{
int highestScore = -1;
foreach (var stream in item.MediaStreams)
{
- if (stream.Type == MediaStreamType.Subtitle && stream.Score.HasValue)
+ if (stream.Type == MediaStreamType.Subtitle
+ && stream.Score.HasValue
+ && stream.Score.Value > highestScore)
{
- if (stream.Score.Value > highestScore)
- {
- highestScore = stream.Score.Value;
- }
+ highestScore = stream.Score.Value;
}
}
@@ -646,7 +594,7 @@ namespace MediaBrowser.Model.Dlna
return item.DefaultSubtitleStreamIndex;
}
- private void SetStreamInfoOptionsFromTranscodingProfile(StreamInfo playlistItem, TranscodingProfile transcodingProfile)
+ private static void SetStreamInfoOptionsFromTranscodingProfile(StreamInfo playlistItem, TranscodingProfile transcodingProfile)
{
if (string.IsNullOrEmpty(transcodingProfile.AudioCodec))
{
@@ -686,12 +634,10 @@ namespace MediaBrowser.Model.Dlna
}
playlistItem.SubProtocol = transcodingProfile.Protocol;
- if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels))
+ if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels)
+ && int.TryParse(transcodingProfile.MaxAudioChannels, NumberStyles.Any, CultureInfo.InvariantCulture, out int transcodingMaxAudioChannels))
{
- if (int.TryParse(transcodingProfile.MaxAudioChannels, NumberStyles.Any, CultureInfo.InvariantCulture, out var transcodingMaxAudioChannels))
- {
- playlistItem.TranscodingMaxAudioChannels = transcodingMaxAudioChannels;
- }
+ playlistItem.TranscodingMaxAudioChannels = transcodingMaxAudioChannels;
}
}
@@ -702,9 +648,7 @@ namespace MediaBrowser.Model.Dlna
throw new ArgumentNullException(nameof(item));
}
- var transcodeReasons = new List<TranscodeReason>();
-
- var playlistItem = new StreamInfo
+ StreamInfo playlistItem = new StreamInfo
{
ItemId = options.ItemId,
MediaType = DlnaProfileType.Video,
@@ -737,6 +681,8 @@ namespace MediaBrowser.Model.Dlna
isEligibleForDirectPlay,
isEligibleForDirectStream);
+ var transcodeReasons = new List<TranscodeReason>();
+
if (isEligibleForDirectPlay || isEligibleForDirectStream)
{
// See if it can be direct played
@@ -803,8 +749,6 @@ namespace MediaBrowser.Model.Dlna
SetStreamInfoOptionsFromTranscodingProfile(playlistItem, transcodingProfile);
- var conditionProcessor = new ConditionProcessor();
-
var isFirstAppliedCodecProfile = true;
foreach (var i in options.Profile.CodecProfiles)
{
@@ -813,26 +757,26 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
{
- int? width = videoStream == null ? null : videoStream.Width;
- int? height = videoStream == null ? null : videoStream.Height;
- int? bitDepth = videoStream == null ? null : videoStream.BitDepth;
- int? videoBitrate = videoStream == null ? null : videoStream.BitRate;
- double? videoLevel = videoStream == null ? null : videoStream.Level;
- string videoProfile = videoStream == null ? null : videoStream.Profile;
+ int? width = videoStream?.Width;
+ int? height = videoStream?.Height;
+ int? bitDepth = videoStream?.BitDepth;
+ int? videoBitrate = videoStream?.BitRate;
+ double? videoLevel = videoStream?.Level;
+ string videoProfile = videoStream?.Profile;
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
- bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
- bool? isInterlaced = videoStream == null ? (bool?)null : videoStream.IsInterlaced;
- string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
- bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
+ bool? isAnamorphic = videoStream?.IsAnamorphic;
+ bool? isInterlaced = videoStream?.IsInterlaced;
+ string videoCodecTag = videoStream?.CodecTag;
+ bool? isAvc = videoStream?.IsAVC;
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp;
- int? packetLength = videoStream == null ? null : videoStream.PacketLength;
- int? refFrames = videoStream == null ? null : videoStream.RefFrames;
+ int? packetLength = videoStream?.PacketLength;
+ int? refFrames = videoStream?.RefFrames;
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
- if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
applyConditions = false;
@@ -876,7 +820,7 @@ namespace MediaBrowser.Model.Dlna
int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
- if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))
+ if (!ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))
{
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
applyConditions = false;
@@ -922,7 +866,7 @@ namespace MediaBrowser.Model.Dlna
return playlistItem;
}
- private int GetDefaultAudioBitrateIfUnknown(MediaStream audioStream)
+ private static int GetDefaultAudioBitrateIfUnknown(MediaStream audioStream)
{
if ((audioStream.Channels ?? 0) >= 6)
{
@@ -932,33 +876,37 @@ namespace MediaBrowser.Model.Dlna
return 192000;
}
- private int GetAudioBitrate(string subProtocol, long maxTotalBitrate, string[] targetAudioCodecs, MediaStream audioStream, StreamInfo item)
+ private static int GetAudioBitrate(string subProtocol, long maxTotalBitrate, string[] targetAudioCodecs, MediaStream audioStream, StreamInfo item)
{
- var targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
+ string targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
- var targetAudioChannels = item.GetTargetAudioChannels(targetAudioCodec);
+ int? targetAudioChannels = item.GetTargetAudioChannels(targetAudioCodec);
- int defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
+ int defaultBitrate;
+ int encoderAudioBitrateLimit = int.MaxValue;
- // Reduce the bitrate if we're downmixing
- if (targetAudioChannels.HasValue && audioStream != null && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
+ if (audioStream == null)
{
- defaultBitrate = targetAudioChannels.Value <= 2 ? 128000 : 192000;
+ defaultBitrate = 192000;
}
-
- int encoderAudioBitrateLimit = int.MaxValue;
-
- if (audioStream != null)
+ else
{
+ if (targetAudioChannels.HasValue && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
+ {
+ // Reduce the bitrate if we're downmixing
+ defaultBitrate = targetAudioChannels.Value < 2 ? 128000 : 192000;
+ }
+ else
+ {
+ defaultBitrate = audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
+ }
+
// Seeing webm encoding failures when source has 1 audio channel and 22k bitrate.
// Any attempts to transcode over 64k will fail
- if (audioStream.Channels.HasValue &&
- audioStream.Channels.Value == 1)
+ if (audioStream.Channels == 1
+ && (audioStream.BitRate ?? 0) < 64000)
{
- if ((audioStream.BitRate ?? 0) < 64000)
- {
- encoderAudioBitrateLimit = 64000;
- }
+ encoderAudioBitrateLimit = 64000;
}
}
@@ -970,19 +918,17 @@ namespace MediaBrowser.Model.Dlna
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
}
- private int GetMaxAudioBitrateForTotalBitrate(long totalBitrate)
+ private static int GetMaxAudioBitrateForTotalBitrate(long totalBitrate)
{
if (totalBitrate <= 640000)
{
return 128000;
}
-
- if (totalBitrate <= 2000000)
+ else if (totalBitrate <= 2000000)
{
return 384000;
}
-
- if (totalBitrate <= 3000000)
+ else if (totalBitrate <= 3000000)
{
return 448000;
}
@@ -990,24 +936,25 @@ namespace MediaBrowser.Model.Dlna
return 640000;
}
- private Tuple<PlayMethod?, List<TranscodeReason>> GetVideoDirectPlayProfile(VideoOptions options,
+ private (PlayMethod?, List<TranscodeReason>) GetVideoDirectPlayProfile(
+ VideoOptions options,
MediaSourceInfo mediaSource,
MediaStream videoStream,
MediaStream audioStream,
bool isEligibleForDirectPlay,
bool isEligibleForDirectStream)
{
- DeviceProfile profile = options.Profile;
-
if (options.ForceDirectPlay)
{
- return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectPlay, new List<TranscodeReason>());
+ return (PlayMethod.DirectPlay, new List<TranscodeReason>());
}
if (options.ForceDirectStream)
{
- return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
+ return (PlayMethod.DirectStream, new List<TranscodeReason>());
}
+ DeviceProfile profile = options.Profile;
+
// See if it can be direct played
DirectPlayProfile directPlay = null;
foreach (var i in profile.DirectPlayProfiles)
@@ -1025,7 +972,7 @@ namespace MediaBrowser.Model.Dlna
profile.Name ?? "Unknown Profile",
mediaSource.Path ?? "Unknown path");
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles));
+ return (null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles));
}
string container = mediaSource.Container;
@@ -1033,8 +980,8 @@ namespace MediaBrowser.Model.Dlna
var conditions = new List<ProfileCondition>();
foreach (var i in profile.ContainerProfiles)
{
- if (i.Type == DlnaProfileType.Video &&
- i.ContainsContainer(container))
+ if (i.Type == DlnaProfileType.Video
+ && i.ContainsContainer(container))
{
foreach (var c in i.Conditions)
{
@@ -1043,29 +990,27 @@ namespace MediaBrowser.Model.Dlna
}
}
- var conditionProcessor = new ConditionProcessor();
-
- int? width = videoStream == null ? null : videoStream.Width;
- int? height = videoStream == null ? null : videoStream.Height;
- int? bitDepth = videoStream == null ? null : videoStream.BitDepth;
- int? videoBitrate = videoStream == null ? null : videoStream.BitRate;
- double? videoLevel = videoStream == null ? null : videoStream.Level;
- string videoProfile = videoStream == null ? null : videoStream.Profile;
+ int? width = videoStream?.Width;
+ int? height = videoStream?.Height;
+ int? bitDepth = videoStream?.BitDepth;
+ int? videoBitrate = videoStream?.BitRate;
+ double? videoLevel = videoStream?.Level;
+ string videoProfile = videoStream?.Profile;
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
- bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
- bool? isInterlaced = videoStream == null ? (bool?)null : videoStream.IsInterlaced;
- string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
- bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
+ bool? isAnamorphic = videoStream?.IsAnamorphic;
+ bool? isInterlaced = videoStream?.IsInterlaced;
+ string videoCodecTag = videoStream?.CodecTag;
+ bool? isAvc = videoStream?.IsAVC;
- int? audioBitrate = audioStream == null ? null : audioStream.BitRate;
- int? audioChannels = audioStream == null ? null : audioStream.Channels;
- string audioProfile = audioStream == null ? null : audioStream.Profile;
- int? audioSampleRate = audioStream == null ? null : audioStream.SampleRate;
- int? audioBitDepth = audioStream == null ? null : audioStream.BitDepth;
+ int? audioBitrate = audioStream?.BitRate;
+ int? audioChannels = audioStream?.Channels;
+ string audioProfile = audioStream?.Profile;
+ int? audioSampleRate = audioStream?.SampleRate;
+ int? audioBitDepth = audioStream?.BitDepth;
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : mediaSource.Timestamp;
- int? packetLength = videoStream == null ? null : videoStream.PacketLength;
- int? refFrames = videoStream == null ? null : videoStream.RefFrames;
+ int? packetLength = videoStream?.PacketLength;
+ int? refFrames = videoStream?.RefFrames;
int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
@@ -1073,20 +1018,20 @@ namespace MediaBrowser.Model.Dlna
// Check container conditions
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!ConditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
var transcodeReasons = transcodeReason.HasValue
? new List<TranscodeReason> { transcodeReason.Value }
- : new List<TranscodeReason> { };
+ : new List<TranscodeReason>();
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
+ return (null, transcodeReasons);
}
}
- string videoCodec = videoStream == null ? null : videoStream.Codec;
+ string videoCodec = videoStream?.Codec;
conditions = new List<ProfileCondition>();
foreach (var i in profile.CodecProfiles)
@@ -1096,7 +1041,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
//LogConditionFailure(profile, "VideoCodecProfile.ApplyConditions", applyCondition, mediaSource);
applyConditions = false;
@@ -1116,23 +1061,22 @@ namespace MediaBrowser.Model.Dlna
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!ConditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
var transcodeReasons = transcodeReason.HasValue
? new List<TranscodeReason> { transcodeReason.Value }
- : new List<TranscodeReason> { };
+ : new List<TranscodeReason>();
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
+ return (null, transcodeReasons);
}
}
if (audioStream != null)
{
string audioCodec = audioStream.Codec;
-
conditions = new List<ProfileCondition>();
bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream);
@@ -1143,7 +1087,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
{
- if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
+ if (!ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
{
//LogConditionFailure(profile, "VideoAudioCodecProfile.ApplyConditions", applyCondition, mediaSource);
applyConditions = false;
@@ -1163,26 +1107,26 @@ namespace MediaBrowser.Model.Dlna
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
+ if (!ConditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
{
LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
var transcodeReasons = transcodeReason.HasValue
? new List<TranscodeReason> { transcodeReason.Value }
- : new List<TranscodeReason> { };
+ : new List<TranscodeReason>();
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
+ return (null, transcodeReasons);
}
}
}
if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
{
- return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
+ return (PlayMethod.DirectStream, new List<TranscodeReason>());
}
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
+ return (null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
}
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
@@ -1197,7 +1141,8 @@ namespace MediaBrowser.Model.Dlna
mediaSource.Path ?? "Unknown path");
}
- private ValueTuple<bool, TranscodeReason?> IsEligibleForDirectPlay(MediaSourceInfo item,
+ private (bool directPlay, TranscodeReason? reason) IsEligibleForDirectPlay(
+ MediaSourceInfo item,
long maxBitrate,
MediaStream subtitleStream,
VideoOptions options,
@@ -1210,21 +1155,23 @@ namespace MediaBrowser.Model.Dlna
if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
{
_logger.LogInformation("Not eligible for {0} due to unsupported subtitles", playMethod);
- return new ValueTuple<bool, TranscodeReason?>(false, TranscodeReason.SubtitleCodecNotSupported);
+ return (false, TranscodeReason.SubtitleCodecNotSupported);
}
}
- var result = IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod);
-
- if (result)
- {
- return new ValueTuple<bool, TranscodeReason?>(result, null);
- }
+ bool result = IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod);
- return new ValueTuple<bool, TranscodeReason?>(result, TranscodeReason.ContainerBitrateExceedsLimit);
+ return (result, result ? (TranscodeReason?)null : TranscodeReason.ContainerBitrateExceedsLimit);
}
- public static SubtitleProfile GetSubtitleProfile(MediaSourceInfo mediaSource, MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, ITranscoderSupport transcoderSupport, string outputContainer, string transcodingSubProtocol)
+ public static SubtitleProfile GetSubtitleProfile(
+ MediaSourceInfo mediaSource,
+ MediaStream subtitleStream,
+ SubtitleProfile[] subtitleProfiles,
+ PlayMethod playMethod,
+ ITranscoderSupport transcoderSupport,
+ string outputContainer,
+ string transcodingSubProtocol)
{
if (!subtitleStream.IsExternal && (playMethod != PlayMethod.Transcode || !string.Equals(transcodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase)))
{
@@ -1301,27 +1248,20 @@ namespace MediaBrowser.Model.Dlna
{
if (!string.IsNullOrEmpty(transcodingContainer))
{
- var normalizedContainers = ContainerProfile.SplitValue(transcodingContainer);
+ string[] normalizedContainers = ContainerProfile.SplitValue(transcodingContainer);
- if (ContainerProfile.ContainsContainer(normalizedContainers, "ts"))
- {
- return false;
- }
- if (ContainerProfile.ContainsContainer(normalizedContainers, "mpegts"))
- {
- return false;
- }
- if (ContainerProfile.ContainsContainer(normalizedContainers, "mp4"))
+ if (ContainerProfile.ContainsContainer(normalizedContainers, "ts")
+ || ContainerProfile.ContainsContainer(normalizedContainers, "mpegts")
+ || ContainerProfile.ContainsContainer(normalizedContainers, "mp4"))
{
return false;
}
- if (ContainerProfile.ContainsContainer(normalizedContainers, "mkv") ||
- ContainerProfile.ContainsContainer(normalizedContainers, "matroska"))
+ else if (ContainerProfile.ContainsContainer(normalizedContainers, "mkv")
+ || ContainerProfile.ContainsContainer(normalizedContainers, "matroska"))
{
return true;
}
}
-
return false;
}
@@ -1388,22 +1328,22 @@ namespace MediaBrowser.Model.Dlna
return true;
}
- var requestedMaxBitrate = maxBitrate > 0 ? maxBitrate : 1000000;
+ long requestedMaxBitrate = maxBitrate > 0 ? maxBitrate : 1000000;
// If we don't know the bitrate, then force a transcode if requested max bitrate is under 40 mbps
- var itemBitrate = item.Bitrate ??
- 40000000;
+ int itemBitrate = item.Bitrate ?? 40000000;
if (itemBitrate > requestedMaxBitrate)
{
- _logger.LogInformation("Bitrate exceeds " + playMethod + " limit: media bitrate: {0}, max bitrate: {1}", itemBitrate.ToString(CultureInfo.InvariantCulture), requestedMaxBitrate.ToString(CultureInfo.InvariantCulture));
+ _logger.LogInformation("Bitrate exceeds {PlayBackMethod} limit: media bitrate: {MediaBitrate}, max bitrate: {MaxBitrate}",
+ playMethod, itemBitrate, requestedMaxBitrate);
return false;
}
return true;
}
- private void ValidateInput(VideoOptions options)
+ private static void ValidateInput(VideoOptions options)
{
ValidateAudioInput(options);
@@ -1418,7 +1358,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- private void ValidateAudioInput(AudioOptions options)
+ private static void ValidateAudioInput(AudioOptions options)
{
if (options.ItemId.Equals(Guid.Empty))
{
@@ -1438,32 +1378,6 @@ namespace MediaBrowser.Model.Dlna
}
}
- private void ApplyTranscodingConditions(StreamInfo item, List<CodecProfile> codecProfiles)
- {
- foreach (var profile in codecProfiles)
- {
- ApplyTranscodingConditions(item, profile);
- }
- }
-
- private void ApplyTranscodingConditions(StreamInfo item, CodecProfile codecProfile)
- {
- var codecs = ContainerProfile.SplitValue(codecProfile.Codec);
- if (codecs.Length == 0)
- {
- ApplyTranscodingConditions(item, codecProfile.Conditions, null, true, true);
- return;
- }
-
- var enableNonQualified = true;
-
- foreach (var codec in codecs)
- {
- ApplyTranscodingConditions(item, codecProfile.Conditions, codec, true, enableNonQualified);
- enableNonQualified = false;
- }
- }
-
private void ApplyTranscodingConditions(StreamInfo item, IEnumerable<ProfileCondition> conditions, string qualifier, bool enableQualifiedConditions, bool enableNonQualifiedConditions)
{
foreach (ProfileCondition condition in conditions)
@@ -1838,7 +1752,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- private bool IsAudioDirectPlaySupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream audioStream)
+ private static bool IsAudioDirectPlaySupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream audioStream)
{
// Check container type
if (!profile.SupportsContainer(item.Container))
@@ -1847,7 +1761,7 @@ namespace MediaBrowser.Model.Dlna
}
// Check audio codec
- string audioCodec = audioStream == null ? null : audioStream.Codec;
+ string audioCodec = audioStream?.Codec;
if (!profile.SupportsAudioCodec(audioCodec))
{
return false;
@@ -1865,20 +1779,16 @@ namespace MediaBrowser.Model.Dlna
}
// Check video codec
- string videoCodec = videoStream == null ? null : videoStream.Codec;
+ string videoCodec = videoStream?.Codec;
if (!profile.SupportsVideoCodec(videoCodec))
{
return false;
}
// Check audio codec
- if (audioStream != null)
+ if (audioStream != null && !profile.SupportsAudioCodec(audioStream.Codec))
{
- string audioCodec = audioStream == null ? null : audioStream.Codec;
- if (!profile.SupportsAudioCodec(audioCodec))
- {
- return false;
- }
+ return false;
}
return true;
diff --git a/MediaBrowser.WebDashboard/jellyfin-web b/MediaBrowser.WebDashboard/jellyfin-web
-Subproject 4678528d0028685b45c7c6daa2e24b72a363535
+Subproject 094c1deae91c51b8bbf8ebb16a55758af110f04
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index 0f0c24a25..dfaa2601f 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -42,8 +42,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Notifications", "Emby.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Naming", "Emby.Naming\Emby.Naming.csproj", "{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "taglib-sharp", "ThirdParty\taglib-sharp\src\taglib-sharp.csproj", "{D45FC504-D06B-41A0-A220-C20B7E8F1304}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.XmlTv", "Emby.XmlTv\Emby.XmlTv\Emby.XmlTv.csproj", "{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IsoMounter", "Emby.IsoMounting\IsoMounter\IsoMounter.csproj", "{9BA471D2-6DB9-4DBF-B3A0-9FB3171F94A6}"
@@ -144,10 +142,6 @@ Global
{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Release|Any CPU.Build.0 = Release|Any CPU
- {D45FC504-D06B-41A0-A220-C20B7E8F1304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D45FC504-D06B-41A0-A220-C20B7E8F1304}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D45FC504-D06B-41A0-A220-C20B7E8F1304}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D45FC504-D06B-41A0-A220-C20B7E8F1304}.Release|Any CPU.Build.0 = Release|Any CPU
{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/Mono.Nat/Upnp/Searchers/UpnpSearcher.cs b/Mono.Nat/Upnp/Searchers/UpnpSearcher.cs
index b70768b6f..3b54c4680 100644
--- a/Mono.Nat/Upnp/Searchers/UpnpSearcher.cs
+++ b/Mono.Nat/Upnp/Searchers/UpnpSearcher.cs
@@ -47,7 +47,6 @@ namespace Mono.Nat
{
public event EventHandler<DeviceEventArgs> DeviceFound;
- private DateTime nextSearch;
private readonly ILogger _logger;
private readonly IHttpClient _httpClient;
@@ -98,11 +97,6 @@ namespace Mono.Nat
{
}
- public DateTime NextSearch
- {
- get { return nextSearch; }
- }
-
private void OnDeviceFound(DeviceEventArgs args)
{
if (DeviceFound != null)
diff --git a/SharedVersion.cs b/SharedVersion.cs
index a29381f63..70c309674 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-[assembly: AssemblyVersion("10.0.2")]
-[assembly: AssemblyFileVersion("10.0.2")]
+[assembly: AssemblyVersion("10.1.0")]
+[assembly: AssemblyFileVersion("10.1.0")]
diff --git a/SocketHttpListener/HttpBase.cs b/SocketHttpListener/HttpBase.cs
index fea91d84b..c386b9374 100644
--- a/SocketHttpListener/HttpBase.cs
+++ b/SocketHttpListener/HttpBase.cs
@@ -13,12 +13,6 @@ namespace SocketHttpListener
#endregion
- #region Internal Fields
-
- internal byte[] EntityBodyData;
-
- #endregion
-
#region Protected Fields
protected const string CrLf = "\r\n";
@@ -37,18 +31,6 @@ namespace SocketHttpListener
#region Public Properties
- public string EntityBody
- {
- get
- {
- var data = EntityBodyData;
-
- return data != null && data.Length > 0
- ? getEncoding(_headers["Content-Type"]).GetString(data, 0, data.Length)
- : string.Empty;
- }
- }
-
public QueryParamCollection Headers => _headers;
public Version ProtocolVersion => _version;
diff --git a/SocketHttpListener/HttpResponse.cs b/SocketHttpListener/HttpResponse.cs
index bcfa4a906..d5d9b4a1c 100644
--- a/SocketHttpListener/HttpResponse.cs
+++ b/SocketHttpListener/HttpResponse.cs
@@ -115,10 +115,6 @@ namespace SocketHttpListener
output.Append(CrLf);
- var entity = EntityBody;
- if (entity.Length > 0)
- output.Append(entity);
-
return output.ToString();
}
diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs
index f11cb0725..e89f4ed9b 100644
--- a/SocketHttpListener/Net/HttpConnection.cs
+++ b/SocketHttpListener/Net/HttpConnection.cs
@@ -32,8 +32,6 @@ namespace SocketHttpListener.Net
int _reuses;
bool _contextBound;
bool secure;
- int _timeout = 90000; // 90k ms for first request, 15k ms from then on
- private Timer _timer;
IPEndPoint local_ep;
HttpListener _lastListener;
X509Certificate cert;
@@ -91,8 +89,6 @@ namespace SocketHttpListener.Net
public async Task Init()
{
- _timer = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
-
if (ssl_stream != null)
{
var enableAsync = true;
@@ -162,14 +158,10 @@ namespace SocketHttpListener.Net
_buffer = new byte[BufferSize];
try
{
- if (_reuses == 1)
- _timeout = 15000;
- //_timer.Change(_timeout, Timeout.Infinite);
_stream.BeginRead(_buffer, 0, BufferSize, s_onreadCallback, this);
}
catch
{
- //_timer.Change(Timeout.Infinite, Timeout.Infinite);
CloseSocket();
Unbind();
}
@@ -216,7 +208,6 @@ namespace SocketHttpListener.Net
private void OnReadInternal(IAsyncResult ares)
{
- //_timer.Change(Timeout.Infinite, Timeout.Infinite);
int nread = -1;
try
{
diff --git a/SocketHttpListener/WebSocket.cs b/SocketHttpListener/WebSocket.cs
index bf400599d..128bc8b97 100644
--- a/SocketHttpListener/WebSocket.cs
+++ b/SocketHttpListener/WebSocket.cs
@@ -24,7 +24,6 @@ namespace SocketHttpListener
{
#region Private Fields
- private string _base64Key;
private Action _closeContext;
private CompressionMethod _compression;
private WebSocketContext _context;
@@ -35,20 +34,12 @@ namespace SocketHttpListener
private object _forMessageEventQueue;
private object _forSend;
private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- private Func<WebSocketContext, string>
- _handshakeRequestChecker;
private Queue<MessageEventArgs> _messageEventQueue;
- private uint _nonceCount;
- private string _origin;
- private bool _preAuth;
private string _protocol;
- private string[] _protocols;
- private Uri _proxyUri;
private volatile WebSocketState _readyState;
private AutoResetEvent _receivePong;
private bool _secure;
private Stream _stream;
- private Uri _uri;
private const string _version = "13";
#endregion
diff --git a/build b/build
index c2daddd84..7d49db72a 100755
--- a/build
+++ b/build
@@ -10,7 +10,7 @@ declare -a actions=( 'build' 'package' 'sign' 'publish' )
# The list of possible platforms, based on directories under 'deployment/'
declare -a platforms=( $(
- find deployment/ -maxdepth 1 -mindepth 1 -type d | sed 's/deployment\///' | sort
+ find deployment/ -maxdepth 1 -mindepth 1 -type d -exec basename {} \; | sort
) )
# The list of standard dependencies required by all build scripts; individual
@@ -171,16 +171,27 @@ if ! git diff-index --quiet HEAD --; then
fi
git fetch --all
-git checkout origin/${web_branch} || {
- echo "ERROR: 'jellyfin-web' branch ${web_branch} is invalid."
- exit 1
-}
+# If this is an official branch name, fetch it from origin
+official_branches_regex="^master$|^dev$|^release-.*$|^hotfix-.*$"
+if [[ ${web_branch} =~ ${official_branches_regex} ]]; then
+ git checkout origin/${web_branch} || {
+ echo "ERROR: 'jellyfin-web' branch 'origin/${web_branch}' is invalid."
+ exit 1
+ }
+# Otherwise, just check out the local branch (for testing, etc.)
+else
+ git checkout ${web_branch} || {
+ echo "ERROR: 'jellyfin-web' branch '${web_branch}' is invalid."
+ exit 1
+ }
+fi
popd
# Execute each platform and action in order, if said action is enabled
pushd deployment/
for target_platform in ${platform[@]}; do
echo -e "> Processing platform ${target_platform}"
+ date_start=$( date +%s )
pushd ${target_platform}
for target_action in ${action[@]}; do
echo -e ">> Processing action ${target_action}"
@@ -199,6 +210,8 @@ for target_platform in ${platform[@]}; do
./clean.sh
fi
fi
+ date_end=$( date +%s )
+ echo -e "> Completed platform ${target_platform} in $( expr ${date_end} - ${date_start} ) seconds."
popd
done
popd
diff --git a/bump_version b/bump_version
index 06a690e19..c3f1a78d5 100755
--- a/bump_version
+++ b/bump_version
@@ -47,10 +47,20 @@ if ! git diff-index --quiet HEAD --; then
fi
git fetch --all
-git checkout origin/${web_branch} || {
- echo "ERROR: 'jellyfin-web' branch ${web_branch} is invalid."
- exit 1
-}
+# If this is an official branch name, fetch it from origin
+official_branches_regex="^master$|^dev$|^release-.*$|^hotfix-.*$"
+if [[ ${web_branch} =~ ${official_branches_regex} ]]; then
+ git checkout origin/${web_branch} || {
+ echo "ERROR: 'jellyfin-web' branch 'origin/${web_branch}' is invalid."
+ exit 1
+ }
+# Otherwise, just check out the local branch (for testing, etc.)
+else
+ git checkout ${web_branch} || {
+ echo "ERROR: 'jellyfin-web' branch '${web_branch}' is invalid."
+ exit 1
+ }
+fi
popd
new_version="$1"
@@ -94,7 +104,7 @@ for repo in ./ MediaBrowser.WebDashboard/jellyfin-web/; do
pushd ${repo}
# Find the last release commit, so we know what's happened since
- last_master_branch="master-${old_version}" # TODO: Set to `release-` for next release, so we can properly parse both repos with the new branch standard
+ last_master_branch="release-${old_version}"
last_master_merge_commit="$(
git log --merges --pretty=oneline \
| grep -F "${last_master_branch}" \
@@ -150,7 +160,7 @@ echo -e "### DEBIAN PACKAGE CHANGELOG: Verify this file looks correct or edit ac
jellyfin (${new_version}-1) unstable; urgency=medium
${changelog_string_deb}
--- Jellyfin Packaging Team <packaging@jellyfin.org> $( date --rfc-2822 )
+ -- Jellyfin Packaging Team <packaging@jellyfin.org> $( date --rfc-2822 )
" >> ${debian_changelog_temp}
cat ${debian_changelog_file} >> ${debian_changelog_temp}
# Edit the file to verify
diff --git a/deployment/common.build.sh b/deployment/common.build.sh
index 7392fd401..c191ec2a1 100755
--- a/deployment/common.build.sh
+++ b/deployment/common.build.sh
@@ -23,8 +23,7 @@ get_version()
(
local ROOT=${1-$DEFAULT_ROOT}
grep "AssemblyVersion" ${ROOT}/SharedVersion.cs \
- | sed -E 's/\[assembly: ?AssemblyVersion\("([0-9\.]+)"\)\]/\1/' \
- | sed -E 's/.0$//'
+ | sed -E 's/\[assembly: ?AssemblyVersion\("([0-9\.]+)"\)\]/\1/'
)
# Run a build
diff --git a/deployment/debian-package-x64/pkg-src/changelog b/deployment/debian-package-x64/pkg-src/changelog
index 825412d89..7f3f12b00 100644
--- a/deployment/debian-package-x64/pkg-src/changelog
+++ b/deployment/debian-package-x64/pkg-src/changelog
@@ -1,3 +1,86 @@
+jellyfin (10.1.0-1) unstable; urgency=medium
+
+ * jellyfin:
+ * PR335 Build scripts and build system consolidation.
+ * PR424 add jellyfin-web as submodule
+ * PR455 Cleanup some small things
+ * PR458 Clean up several minor issues and add TODOs
+ * PR506 Removing tabs and trailing whitespace
+ * PR508 Update internal versioning and user agents.
+ * PR516 Remove useless properties from IEnvironmentInfo
+ * PR520 Fix potential bug where aspect ratio would be incorrectly calculated
+ * PR534 Add linux-arm and linux-arm64 native NuGet dependency.
+ * PR540 Update Emby API keys to our own
+ * PR541 Change ItemId to Guid in ProviderManager
+ * PR556 Fix "Password Reset by PIN" page
+ * PR562 Fix error with uppercase photo extension and fix typo in a log line
+ * PR563 Update dev from master
+ * PR566 Avoid printing stacktrace when bind to port 1900 fails
+ * PR567 Shutdown gracefully when recieving a termination signal
+ * PR571 Add more NuGet metadata properties
+ * PR575 Reformat all C# server code to conform with code standards
+ * PR576 Add code analysers for debug builds
+ * PR580 Fix Docker build
+ * PR582 Replace custom image parser with Skia
+ * PR587 Add nuget info to Emby.Naming
+ * PR589 Ensure config and log folders exist
+ * PR596 Fix indentation for xml files
+ * PR598 Remove MediaBrowser.Text for license violations and hackiness
+ * PR606 Slim down docker image
+ * PR613 Update MediaEncoding
+ * PR616 Add Swagger documentation
+ * PR619 Really slim down Docker container
+ * PR621 Minor improvements to library scan code
+ * PR622 Add unified build script and bump_version script
+ * PR623 Replaced injections of ILogger with ILoggerFactory
+ * PR625 Update taglib-sharp
+ * PR626 Fix extra type name in parameter, add out keyword
+ * PR627 Use string for ApplicationVersion
+ * PR628 Update Product Name (User-Agent)
+ * PR629 Fix subtitle converter misinterpreting 0 valued endTimeTicks
+ * PR631 Cleanup ImageProcessor and SkiaEncoder
+ * PR634 Replace our TVDB key with @drakus72's which is V1
+ * PR636 Allow subtitle extraction and conversion in direct streaming
+ * PR637 Remove unused font
+ * PR638 Removed XmlTv testfiles and nuget install
+ * PR646: Fix infinite loop bug on subtitle.m3u8 request
+ * PR655: Support trying local branches in submodule
+ * PR661: Fix NullRef from progress report
+ * PR666: Add cross-platform build for arm64
+ * jellyfin-web:
+ * PR1: Change webcomponents to non-minified version
+ * PR4: Fix user profile regression
+ * PR6: Make icon into proper ico and large PNG
+ * PR7: Fix firefox failing to set password for users with no password set
+ * PR8: Remove premiere stuff and fix crashes caused by earlier removals
+ * PR12: Fix return from PIN reset to index.html
+ * PR13: Send android clients to select server before login
+ * PR14: Reimplement page to add server
+ * PR16: Fix spinning circle at the end of config wizard
+ * PR17: Fix directorybrower not resetting scroll
+ * PR19: Set union merge for CONTRIBUTORS.md
+ * PR20: Show album thumbnail and artist image in page itemdetail
+ * PR26: Make the card titles clickable
+ * PR27: Stop pagination and adding a library from being able to trigger multiple times
+ * PR28: Add transparent nav bar to BlueRadiance theme CSS
+ * PR29: Clean up imageuploader
+ * PR30: Remove iap and simplify registrationservices
+ * PR36: Open videos in fullscreen on android devices
+ * PR37: Remove broken features from web interface
+ * PR38: Fix inconsistent UI coloring around settings drawer
+ * PR39: Remove back button from dashboard and metadata manager
+ * PR42: Fix Home backdrop not loading
+ * PR43: Filter videos by audio stream language
+ * PR44: Remove filter from library collection type options
+ * PR45: Fix data-backbutton logic
+ * PR46: Minor changes to navbar elements
+ * PR48: Remove Sync code
+ * PR52: Fix progress color
+ * PR53: Fix user tabs color
+ * PR54: Add back button to server dashboard
+
+ -- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 20 Jan 2019 23:19:46 -0500
+
jellyfin (10.0.2-1) unstable; urgency=medium
* Hotfix release
diff --git a/deployment/fedora-package-x64/clean.sh b/deployment/fedora-package-x64/clean.sh
index 3df2d7796..d7233208f 100755
--- a/deployment/fedora-package-x64/clean.sh
+++ b/deployment/fedora-package-x64/clean.sh
@@ -4,4 +4,15 @@ source ../common.build.sh
VERSION=`get_version ../..`
-clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="`pwd`/pkg-dist-tmp"
+pkg_src_dir="`pwd`/pkg-src"
+image_name="jellyfin-rpmbuild"
+docker_sudo=""
+if ! $(id -Gn | grep -q 'docker') && [ ! ${EUID:-1000} -eq 0 ] && \
+ [ ! $USER == "root" ] && ! $(echo "$OSTYPE" | grep -q "darwin"); then
+ docker_sudo=sudo
+fi
+
+$docker_sudo docker image rm $image_name --force
+rm -rf "$package_temporary_dir"
+rm -rf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz"
diff --git a/deployment/fedora-package-x64/package.sh b/deployment/fedora-package-x64/package.sh
index 416c8213b..d459cdb24 100755
--- a/deployment/fedora-package-x64/package.sh
+++ b/deployment/fedora-package-x64/package.sh
@@ -18,10 +18,15 @@ output_dir="`pwd`/pkg-dist"
pkg_src_dir="`pwd`/pkg-src"
current_user="`whoami`"
image_name="jellyfin-rpmbuild"
+docker_sudo=""
+if ! $(id -Gn | grep -q 'docker') && [ ! ${EUID:-1000} -eq 0 ] && \
+ [ ! $USER == "root" ] && ! $(echo "$OSTYPE" | grep -q "darwin"); then
+ docker_sudo=sudo
+fi
cleanup() {
set +o errexit
- docker image rm $image_name --force
+ $docker_sudo docker image rm $image_name --force
rm -rf "$package_temporary_dir"
rm -rf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz"
}
@@ -30,7 +35,7 @@ GNU_TAR=1
mkdir -p "$package_temporary_dir"
echo "Bundling all sources for RPM build."
tar \
---transform "s,^\.,jellyfin-${VERSION}" \
+--transform "s,^\.,jellyfin-${VERSION}," \
--exclude='.git*' \
--exclude='**/.git' \
--exclude='**/.hg' \
@@ -42,10 +47,8 @@ tar \
--exclude='**/.nuget' \
--exclude='*.deb' \
--exclude='*.rpm' \
--Jcvf \
-"$package_temporary_dir/jellyfin-${VERSION}.tar.xz" \
--C "../.." \
-./ || true && GNU_TAR=0
+-zcf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz" \
+-C "../.." ./ || GNU_TAR=0
if [ $GNU_TAR -eq 0 ]; then
echo "The installed tar binary did not support --transform. Using workaround."
@@ -75,9 +78,9 @@ if [ $GNU_TAR -eq 0 ]; then
tar -zcf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz" -C "$package_temporary_dir" "jellyfin-${VERSION}"
fi
-docker build ../.. -t "$image_name" -f ./Dockerfile
+$docker_sudo docker build ../.. -t "$image_name" -f ./Dockerfile
mkdir -p "$output_dir"
-docker run --rm -v "$package_temporary_dir:/temp" "$image_name" sh -c 'find /build/rpmbuild -maxdepth 3 -type f -name "jellyfin*.rpm" -exec mv {} /temp \;'
+$docker_sudo docker run --rm -v "$package_temporary_dir:/temp" "$image_name" sh -c 'find /build/rpmbuild -maxdepth 3 -type f -name "jellyfin*.rpm" -exec mv {} /temp \;'
chown -R "$current_user" "$package_temporary_dir" \
|| sudo chown -R "$current_user" "$package_temporary_dir"
mv "$package_temporary_dir"/*.rpm "$output_dir"
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.spec b/deployment/fedora-package-x64/pkg-src/jellyfin.spec
index e304fe442..6a4a5870b 100644
--- a/deployment/fedora-package-x64/pkg-src/jellyfin.spec
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.spec
@@ -1,13 +1,13 @@
%global debug_package %{nil}
# jellyfin tag to package
-%global gittag v10.0.2
+%global gittag v10.1.0
# Taglib-sharp commit of the submodule since github archive doesn't include submodules
%global taglib_commit ee5ab21742b71fd1b87ee24895582327e9e04776
%global taglib_shortcommit %(c=%{taglib_commit}; echo ${c:0:7})
AutoReq: no
Name: jellyfin
-Version: 10.0.2
+Version: 10.1.0
Release: 1%{?dist}
Summary: The Free Software Media Browser
License: GPLv2
@@ -135,5 +135,84 @@ fi
%systemd_postun_with_restart jellyfin.service
%changelog
+* Sun Jan 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
+- jellyfin:
+- PR335 Build scripts and build system consolidation.
+- PR424 add jellyfin-web as submodule
+- PR455 Cleanup some small things
+- PR458 Clean up several minor issues and add TODOs
+- PR506 Removing tabs and trailing whitespace
+- PR508 Update internal versioning and user agents.
+- PR516 Remove useless properties from IEnvironmentInfo
+- PR520 Fix potential bug where aspect ratio would be incorrectly calculated
+- PR534 Add linux-arm and linux-arm64 native NuGet dependency.
+- PR540 Update Emby API keys to our own
+- PR541 Change ItemId to Guid in ProviderManager
+- PR556 Fix "Password Reset by PIN" page
+- PR562 Fix error with uppercase photo extension and fix typo in a log line
+- PR563 Update dev from master
+- PR566 Avoid printing stacktrace when bind to port 1900 fails
+- PR567 Shutdown gracefully when recieving a termination signal
+- PR571 Add more NuGet metadata properties
+- PR575 Reformat all C# server code to conform with code standards
+- PR576 Add code analysers for debug builds
+- PR580 Fix Docker build
+- PR582 Replace custom image parser with Skia
+- PR587 Add nuget info to Emby.Naming
+- PR589 Ensure config and log folders exist
+- PR596 Fix indentation for xml files
+- PR598 Remove MediaBrowser.Text for license violations and hackiness
+- PR606 Slim down docker image
+- PR613 Update MediaEncoding
+- PR616 Add Swagger documentation
+- PR619 Really slim down Docker container
+- PR621 Minor improvements to library scan code
+- PR622 Add unified build script and bump_version script
+- PR623 Replaced injections of ILogger with ILoggerFactory
+- PR625 Update taglib-sharp
+- PR626 Fix extra type name in parameter, add out keyword
+- PR627 Use string for ApplicationVersion
+- PR628 Update Product Name (User-Agent)
+- PR629 Fix subtitle converter misinterpreting 0 valued endTimeTicks
+- PR631 Cleanup ImageProcessor and SkiaEncoder
+- PR634 Replace our TVDB key with @drakus72's which is V1
+- PR636 Allow subtitle extraction and conversion in direct streaming
+- PR637 Remove unused font
+- PR638 Removed XmlTv testfiles and nuget install
+- PR646: Fix infinite loop bug on subtitle.m3u8 request
+- PR655: Support trying local branches in submodule
+- PR661: Fix NullRef from progress report
+- PR666: Add cross-platform build for arm64
+- jellyfin-web:
+- PR1: Change webcomponents to non-minified version
+- PR4: Fix user profile regression
+- PR6: Make icon into proper ico and large PNG
+- PR7: Fix firefox failing to set password for users with no password set
+- PR8: Remove premiere stuff and fix crashes caused by earlier removals
+- PR12: Fix return from PIN reset to index.html
+- PR13: Send android clients to select server before login
+- PR14: Reimplement page to add server
+- PR16: Fix spinning circle at the end of config wizard
+- PR17: Fix directorybrower not resetting scroll
+- PR19: Set union merge for CONTRIBUTORS.md
+- PR20: Show album thumbnail and artist image in page itemdetail
+- PR26: Make the card titles clickable
+- PR27: Stop pagination and adding a library from being able to trigger multiple times
+- PR28: Add transparent nav bar to BlueRadiance theme CSS
+- PR29: Clean up imageuploader
+- PR30: Remove iap and simplify registrationservices
+- PR36: Open videos in fullscreen on android devices
+- PR37: Remove broken features from web interface
+- PR38: Fix inconsistent UI coloring around settings drawer
+- PR39: Remove back button from dashboard and metadata manager
+- PR42: Fix Home backdrop not loading
+- PR43: Filter videos by audio stream language
+- PR44: Remove filter from library collection type options
+- PR45: Fix data-backbutton logic
+- PR46: Minor changes to navbar elements
+- PR48: Remove Sync code
+- PR52: Fix progress color
+- PR53: Fix user tabs color
+- PR54: Add back button to server dashboard
* Fri Jan 11 2019 Thomas Büttner <thomas@vergesslicher.tech> - 10.0.2-1
- TODO Changelog for 10.0.2
diff --git a/jellyfin.ruleset b/jellyfin.ruleset
new file mode 100644
index 000000000..0f8c9aa02
--- /dev/null
+++ b/jellyfin.ruleset
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RuleSet Name="Rules for Jellyfin.Server" Description="Code analysis rules for Jellyfin.Server.csproj" ToolsVersion="14.0">
+ <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
+ <!-- disable warning SA1101: Prefix local calls with 'this.' -->
+ <Rule Id="SA1101" Action="None" />
+ <!-- disable warning SA1200: 'using' directive must appear within a namespace declaration -->
+ <Rule Id="SA1200" Action="None" />
+ <!-- disable warning SA1309: Fields must not begin with an underscore -->
+ <Rule Id="SA1309" Action="None" />
+ <!-- disable warning SA1633: The file header is missing or not located at the top of the file -->
+ <Rule Id="SA1633" Action="None" />
+ </Rules>
+</RuleSet>