diff options
30 files changed, 325 insertions, 261 deletions
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index d2f635e56..81c4d3d16 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -932,13 +932,7 @@ namespace Emby.Dlna.Didl private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer) { - ImageDownloadInfo imageInfo = null; - - // Finally, just use the image from the item - if (imageInfo == null) - { - imageInfo = GetImageInfo(item); - } + ImageDownloadInfo imageInfo = GetImageInfo(item);; if (imageInfo == null) { diff --git a/Emby.Drawing/SkiaEncoder.cs b/Emby.Drawing/SkiaEncoder.cs index 87e0eca21..9883b3cca 100644 --- a/Emby.Drawing/SkiaEncoder.cs +++ b/Emby.Drawing/SkiaEncoder.cs @@ -270,17 +270,10 @@ namespace Emby.Drawing // create the bitmap var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack); - if (bitmap != null) - { - // decode - codec.GetPixels(bitmap.Info, bitmap.GetPixels()); + // decode + codec.GetPixels(bitmap.Info, bitmap.GetPixels()); - origin = codec.EncodedOrigin; - } - else - { - origin = GetSKEncodedOrigin(orientation); - } + origin = codec.EncodedOrigin; return bitmap; } diff --git a/Emby.Naming/AudioBook/AudioBookResolver.cs b/Emby.Naming/AudioBook/AudioBookResolver.cs index f8f13bc5e..67451a639 100644 --- a/Emby.Naming/AudioBook/AudioBookResolver.cs +++ b/Emby.Naming/AudioBook/AudioBookResolver.cs @@ -30,8 +30,11 @@ namespace Emby.Naming.AudioBook { throw new ArgumentNullException(nameof(path)); } - if (IsDirectory) + + if (IsDirectory) // TODO + { return null; + } var extension = Path.GetExtension(path) ?? string.Empty; // Check supported extensions diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 660547c85..a306b0169 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -681,22 +681,17 @@ namespace Emby.Server.Implementations.Channels // Find the corresponding channel provider plugin var channelProvider = GetChannelProvider(channel); - var user = query.User; - - ChannelItemSortField? sortField = null; - var sortDescending = false; - - var parentItem = !query.ParentId.Equals(Guid.Empty) ? _libraryManager.GetItemById(query.ParentId) : channel; + var parentItem = query.ParentId == Guid.Empty ? channel : _libraryManager.GetItemById(query.ParentId); var itemsResult = await GetChannelItems(channelProvider, - user, + query.User, parentItem is Channel ? null : parentItem.ExternalId, - sortField, - sortDescending, + null, + false, cancellationToken) .ConfigureAwait(false); - if (query.ParentId.Equals(Guid.Empty)) + if (query.ParentId == Guid.Empty) { query.Parent = channel; } diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs index c32c91670..7aedba9b3 100644 --- a/Emby.Server.Implementations/HttpServer/FileWriter.cs +++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs @@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.HttpServer private long RangeStart { get; set; } private long RangeEnd { get; set; } private long RangeLength { get; set; } - private long TotalContentLength { get; set; } + public long TotalContentLength { get; set; } public Action OnComplete { get; set; } public Action OnError { get; set; } diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 8b60d61d4..0ad4d8406 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -5,6 +5,7 @@ using System.IO; using System.IO.Compression; using System.Net; using System.Runtime.Serialization; +using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Xml; @@ -423,13 +424,11 @@ namespace Emby.Server.Implementations.HttpServer /// </summary> private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType) { - responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString); - bool noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1; if (!noCache) { - if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration)) + if (IsNotModified(requestContext, cacheKey)) { AddAgeHeader(responseHeaders, lastDateModified); AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration); @@ -442,7 +441,7 @@ namespace Emby.Server.Implementations.HttpServer } } - AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration); + AddCachingHeaders(responseHeaders, cacheKeyString, cacheDuration); return null; } @@ -532,10 +531,11 @@ namespace Emby.Server.Implementations.HttpServer public async Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options) { - var cacheKey = options.CacheKey; options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - var contentType = options.ContentType; + var contentType = options.ContentType; + var etag = requestContext.Headers.Get("If-None-Match"); + var cacheKey = etag != null ? new Guid(etag.Trim('\"')) : Guid.Empty; if (!cacheKey.Equals(Guid.Empty)) { var key = cacheKey.ToString("N"); @@ -554,8 +554,6 @@ namespace Emby.Server.Implementations.HttpServer var factoryFn = options.ContentFactory; var responseHeaders = options.ResponseHeaders; - //var requestedCompressionType = GetCompressionType(requestContext); - var rangeHeader = requestContext.Headers.Get("Range"); if (!isHeadRequest && !string.IsNullOrEmpty(options.Path)) @@ -568,10 +566,21 @@ namespace Emby.Server.Implementations.HttpServer }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); + // Generate an ETag based on identifying information - TODO read contents from filesystem instead? + var responseId = $"{hasHeaders.ContentType}{options.Path}{hasHeaders.TotalContentLength}"; + var hashedId = MD5.Create().ComputeHash(Encoding.Default.GetBytes(responseId)); + hasHeaders.Headers["ETag"] = new Guid(hashedId).ToString("N"); + return hasHeaders; } var stream = await factoryFn().ConfigureAwait(false); + // Generate an etag based on stream content + var streamHash = MD5.Create().ComputeHash(stream); + var newEtag = new Guid(streamHash).ToString("N"); + + // reset position so the response can re-use it -- TODO is this ok? + stream.Position = 0; var totalContentLength = options.ContentLength; if (!totalContentLength.HasValue) @@ -594,6 +603,7 @@ namespace Emby.Server.Implementations.HttpServer }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); + hasHeaders.Headers["ETag"] = newEtag; return hasHeaders; } else @@ -618,6 +628,7 @@ namespace Emby.Server.Implementations.HttpServer }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); + hasHeaders.Headers["ETag"] = newEtag; return hasHeaders; } } @@ -630,16 +641,8 @@ namespace Emby.Server.Implementations.HttpServer /// <summary> /// Adds the caching responseHeaders. /// </summary> - private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) + private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration) { - // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant - // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching - if (lastDateModified.HasValue && (string.IsNullOrEmpty(cacheKey) || cacheDuration.HasValue)) - { - AddAgeHeader(responseHeaders, lastDateModified); - responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r"); - } - if (cacheDuration.HasValue) { responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds); @@ -692,28 +695,15 @@ namespace Emby.Server.Implementations.HttpServer /// <param name="lastDateModified">The last date modified.</param> /// <param name="cacheDuration">Duration of the cache.</param> /// <returns><c>true</c> if [is not modified] [the specified cache key]; otherwise, <c>false</c>.</returns> - private bool IsNotModified(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) + private bool IsNotModified(IRequest requestContext, Guid cacheKey) { - //var isNotModified = true; - - var ifModifiedSinceHeader = requestContext.Headers.Get("If-Modified-Since"); - - if (!string.IsNullOrEmpty(ifModifiedSinceHeader) - && DateTime.TryParse(ifModifiedSinceHeader, out DateTime ifModifiedSince) - && IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified)) - { - return true; - } - var ifNoneMatchHeader = requestContext.Headers.Get("If-None-Match"); bool hasCacheKey = !cacheKey.Equals(Guid.Empty); // Validate If-None-Match - if ((hasCacheKey && !string.IsNullOrEmpty(ifNoneMatchHeader))) + if (hasCacheKey && !string.IsNullOrEmpty(ifNoneMatchHeader)) { - ifNoneMatchHeader = (ifNoneMatchHeader ?? string.Empty).Trim('\"'); - if (Guid.TryParse(ifNoneMatchHeader, out var ifNoneMatch) && cacheKey.Equals(ifNoneMatch)) { diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 0adc5553b..1ed838893 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -469,7 +469,7 @@ namespace Emby.Server.Implementations.Library } // TODO: Don't hardcode this - var isAudio = false; + const bool isAudio = false; try { @@ -480,9 +480,11 @@ namespace Emby.Server.Implementations.Library else { // hack - these two values were taken from LiveTVMediaSourceProvider - var cacheKey = request.OpenToken; + string cacheKey = request.OpenToken; - await new LiveStreamHelper(_mediaEncoder(), _logger, _jsonSerializer, _appPaths).AddMediaInfoWithProbe(mediaSource, isAudio, cacheKey, true, cancellationToken).ConfigureAwait(false); + await new LiveStreamHelper(_mediaEncoder(), _logger, _jsonSerializer, _appPaths) + .AddMediaInfoWithProbe(mediaSource, isAudio, cacheKey, true, cancellationToken) + .ConfigureAwait(false); } } catch (Exception ex) @@ -491,6 +493,7 @@ namespace Emby.Server.Implementations.Library AddMediaInfo(mediaSource, isAudio); } + // TODO: @bond Fix var json = _jsonSerializer.SerializeToString(mediaSource); _logger.LogInformation("Live stream opened: " + json); var clone = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json); diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs index baa665fce..e39192d28 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs @@ -86,12 +86,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio .Where(i => !LibraryManager.IgnoreFile(i, args.Parent)) .ToList(); - if (isBooksCollectionType) - { - return FindAudio<AudioBook>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false); - } - - return null; + return FindAudio<AudioBook>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false); } if (LibraryManager.IsAudioFile(args.Path, libraryOptions)) @@ -145,36 +140,19 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio private T FindAudio<T>(ItemResolveArgs args, string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool parseName) where T : MediaBrowser.Controller.Entities.Audio.Audio, new() { - var multiDiscFolders = new List<FileSystemMetadata>(); - - var libraryOptions = args.GetLibraryOptions(); - var filesFromOtherItems = new List<FileSystemMetadata>(); - // TODO: Allow GetMultiDiscMovie in here - var supportsMultiVersion = false; + const bool supportsMultiVersion = false; var result = ResolveMultipleAudio<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion, collectionType, parseName) ?? new MultiItemResolverResult(); if (result.Items.Count == 1) { - var videoPath = result.Items[0].Path; - // If we were supporting this we'd be checking filesFromOtherItems - var hasOtherItems = false; - - if (!hasOtherItems) - { - var item = (T)result.Items[0]; - item.IsInMixedFolder = false; - item.Name = Path.GetFileName(item.ContainingFolderPath); - return item; - } - } - - if (result.Items.Count == 0 && multiDiscFolders.Count > 0) - { - //return GetMultiDiscAudio<T>(multiDiscFolders, directoryService); + var item = (T)result.Items[0]; + item.IsInMixedFolder = false; + item.Name = Path.GetFileName(item.ContainingFolderPath); + return item; } return null; @@ -194,11 +172,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio { leftOver.Add(child); } - else if (IsIgnored(child.Name)) - { - - } - else + else if (!IsIgnored(child.Name)) { files.Add(child); } diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index e48213dbb..472a3f105 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -410,7 +410,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies } // TODO: Allow GetMultiDiscMovie in here - var supportsMultiVersion = true; + const bool supportsMultiVersion = true; var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion, collectionType, parseName) ?? new MultiItemResolverResult(); diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index 8ef227689..5c95534ec 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -153,16 +153,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV var namingOptions = ((LibraryManager)libraryManager).GetNamingOptions(); var episodeResolver = new Naming.TV.EpisodeResolver(namingOptions); - bool? isNamed = null; - bool? isOptimistic = null; - if (!isTvContentType) - { - isNamed = true; - isOptimistic = false; - } - - var episodeInfo = episodeResolver.Resolve(fullName, false, isNamed, isOptimistic, fillExtendedInfo: false); + var episodeInfo = episodeResolver.Resolve(fullName, false, true, false, fillExtendedInfo: false); if (episodeInfo != null && episodeInfo.EpisodeNumber.HasValue) { return true; diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index d5bc3d332..6139659b7 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -322,17 +322,14 @@ namespace Emby.Server.Implementations.Library throw new SecurityException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name)); } - if (user != null) + if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(remoteEndPoint)) { - if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(remoteEndPoint)) - { - throw new SecurityException("Forbidden."); - } + throw new SecurityException("Forbidden."); + } - if (!user.IsParentalScheduleAllowed()) - { - throw new SecurityException("User is not allowed access at this time."); - } + if (!user.IsParentalScheduleAllowed()) + { + throw new SecurityException("User is not allowed access at this time."); } // Update LastActivityDate and LastLoginDate, then save @@ -463,26 +460,26 @@ namespace Emby.Server.Implementations.Library { user.Policy.InvalidLoginAttemptCount = newValue; - var maxCount = user.Policy.IsAdministrator ? - 3 : - 5; + var maxCount = user.Policy.IsAdministrator ? 3 : 5; + // TODO: Fix + /* var fireLockout = false; if (newValue >= maxCount) { - //_logger.LogDebug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture)); - //user.Policy.IsDisabled = true; + _logger.LogDebug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture)); + user.Policy.IsDisabled = true; - //fireLockout = true; - } + fireLockout = true; + }*/ UpdateUserPolicy(user, user.Policy, false); - if (fireLockout) + /* if (fireLockout) { UserLockedOut?.Invoke(this, new GenericEventArgs<User>(user)); - } + }*/ } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 64e5affd7..9e11494c9 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1133,8 +1133,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV IgnoreIndex = true }; - var isAudio = false; - await new LiveStreamHelper(_mediaEncoder, _logger, _jsonSerializer, _config.CommonApplicationPaths).AddMediaInfoWithProbe(stream, isAudio, false, cancellationToken).ConfigureAwait(false); + await new LiveStreamHelper(_mediaEncoder, _logger, _jsonSerializer, _config.CommonApplicationPaths) + .AddMediaInfoWithProbe(stream, false, false, cancellationToken).ConfigureAwait(false); return new List<MediaSourceInfo> { @@ -1149,12 +1149,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV public Task RecordLiveStream(string id, CancellationToken cancellationToken) { - return Task.FromResult(0); + return Task.CompletedTask; } public Task ResetTuner(string id, CancellationToken cancellationToken) { - return Task.FromResult(0); + return Task.CompletedTask; } async void _timerProvider_TimerFired(object sender, GenericEventArgs<TimerInfo> e) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index c09ee9348..c11a85027 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -175,12 +175,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } var videoStream = mediaSource.VideoStream; - string videoDecoder = null; - - if (!string.IsNullOrEmpty(videoDecoder)) - { - inputModifier += " " + videoDecoder; - } if (mediaSource.ReadAtNativeFramerate) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index e8e4bc723..77b09a83d 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -354,10 +354,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun int? height = null; bool isInterlaced = true; string videoCodec = null; - string audioCodec = null; int? videoBitrate = null; - int? audioBitrate = null; var isHd = channelInfo.IsHD ?? true; @@ -427,20 +425,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - if (channelInfo != null) + if (string.IsNullOrWhiteSpace(videoCodec)) { - if (string.IsNullOrWhiteSpace(videoCodec)) - { - videoCodec = channelInfo.VideoCodec; - } - audioCodec = channelInfo.AudioCodec; + videoCodec = channelInfo.VideoCodec; + } + string audioCodec = channelInfo.AudioCodec; - if (!videoBitrate.HasValue) - { - videoBitrate = isHd ? 15000000 : 2000000; - } - audioBitrate = isHd ? 448000 : 192000; + if (!videoBitrate.HasValue) + { + videoBitrate = isHd ? 15000000 : 2000000; } + int? audioBitrate = isHd ? 448000 : 192000; // normalize if (string.Equals(videoCodec, "mpeg2", StringComparison.OrdinalIgnoreCase)) 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 2f14d1c52..fef7de512 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -222,7 +222,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() @@ -332,11 +332,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.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/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/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/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/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/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> |
