diff options
| author | Luke <luke.pulverenti@gmail.com> | 2016-12-28 16:13:12 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-12-28 16:13:12 -0500 |
| commit | 2cb0f3eed635bb468b3672d08dca9a720b4fb48f (patch) | |
| tree | 1a0d7c53ec148619ae966a81187413a33ca9a8a4 /Emby.Server.Implementations | |
| parent | e47ccdce4247b93faa6d27849b255aac83324c42 (diff) | |
| parent | c10b152018967ddafe72efbccfe8ca6c586cbf04 (diff) | |
Merge pull request #2372 from MediaBrowser/beta
Beta
Diffstat (limited to 'Emby.Server.Implementations')
25 files changed, 285 insertions, 225 deletions
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 0df916ded3..f7dc930097 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -79,21 +79,6 @@ namespace Emby.Server.Implementations.Channels _channels = channels.ToArray(); } - public string ChannelDownloadPath - { - get - { - var options = _config.GetChannelsConfiguration(); - - if (!string.IsNullOrWhiteSpace(options.DownloadPath)) - { - return options.DownloadPath; - } - - return Path.Combine(_config.ApplicationPaths.ProgramDataPath, "channels"); - } - } - private IEnumerable<IChannel> GetAllChannels() { return _channels @@ -288,7 +273,7 @@ namespace Emby.Server.Implementations.Channels _jsonSerializer.SerializeToFile(mediaSources, path); } - public async Task<IEnumerable<MediaSourceInfo>> GetStaticMediaSources(BaseItem item, bool includeCachedVersions, CancellationToken cancellationToken) + public async Task<IEnumerable<MediaSourceInfo>> GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken) { IEnumerable<ChannelMediaInfo> results = new List<ChannelMediaInfo>(); var video = item as Video; @@ -302,17 +287,9 @@ namespace Emby.Server.Implementations.Channels results = audio.ChannelMediaSources ?? GetSavedMediaSources(audio); } - var sources = SortMediaInfoResults(results) + return SortMediaInfoResults(results) .Select(i => GetMediaSource(item, i)) .ToList(); - - if (includeCachedVersions) - { - var cachedVersions = GetCachedChannelItemMediaSources(item); - sources.InsertRange(0, cachedVersions); - } - - return sources; } public async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(BaseItem item, CancellationToken cancellationToken) @@ -334,14 +311,9 @@ namespace Emby.Server.Implementations.Channels results = new List<ChannelMediaInfo>(); } - var list = SortMediaInfoResults(results) + return SortMediaInfoResults(results) .Select(i => GetMediaSource(item, i)) .ToList(); - - var cachedVersions = GetCachedChannelItemMediaSources(item); - list.InsertRange(0, cachedVersions); - - return list; } private readonly ConcurrentDictionary<string, Tuple<DateTime, List<ChannelMediaInfo>>> _channelItemMediaInfo = @@ -369,55 +341,6 @@ namespace Emby.Server.Implementations.Channels return list; } - private IEnumerable<MediaSourceInfo> GetCachedChannelItemMediaSources(BaseItem item) - { - var filenamePrefix = item.Id.ToString("N"); - var parentPath = Path.Combine(ChannelDownloadPath, item.ChannelId); - - try - { - var files = _fileSystem.GetFiles(parentPath); - - if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) - { - files = files.Where(i => _libraryManager.IsVideoFile(i.FullName)); - } - else - { - files = files.Where(i => _libraryManager.IsAudioFile(i.FullName)); - } - - var file = files - .FirstOrDefault(i => i.Name.StartsWith(filenamePrefix, StringComparison.OrdinalIgnoreCase)); - - if (file != null) - { - var cachedItem = _libraryManager.ResolvePath(file); - - if (cachedItem != null) - { - var hasMediaSources = _libraryManager.GetItemById(cachedItem.Id) as IHasMediaSources; - - if (hasMediaSources != null) - { - var source = hasMediaSources.GetMediaSources(true).FirstOrDefault(); - - if (source != null) - { - return new[] { source }; - } - } - } - } - } - catch (IOException) - { - - } - - return new List<MediaSourceInfo>(); - } - private MediaSourceInfo GetMediaSource(BaseItem item, ChannelMediaInfo info) { var source = info.ToMediaSource(); diff --git a/Emby.Server.Implementations/Connect/ConnectManager.cs b/Emby.Server.Implementations/Connect/ConnectManager.cs index b7faaa9013..8c8b7b0268 100644 --- a/Emby.Server.Implementations/Connect/ConnectManager.cs +++ b/Emby.Server.Implementations/Connect/ConnectManager.cs @@ -570,9 +570,9 @@ namespace Emby.Server.Implementations.Connect } catch (HttpException ex) { - if (!ex.StatusCode.HasValue) + if (!ex.StatusCode.HasValue || ex.IsTimedOut) { - throw; + throw new Exception("Unable to invite guest, " + ex.Message, ex); } // If they entered a username, then whatever the error is just throw it, for example, user not found diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs index d6ad0ba8ab..783258a138 100644 --- a/Emby.Server.Implementations/Data/SqliteExtensions.cs +++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs @@ -346,6 +346,18 @@ namespace Emby.Server.Implementations.Data } } + public static void TryBind(this IStatement statement, string name, double? value) + { + if (value.HasValue) + { + TryBind(statement, name, value.Value); + } + else + { + TryBindNull(statement, name); + } + } + public static void TryBind(this IStatement statement, string name, int? value) { if (value.HasValue) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 8e6a277a47..8c16216b95 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -5267,11 +5267,19 @@ namespace Emby.Server.Implementations.Data { foreach (var pair in values) { + var itemValue = pair.Item2; + + // Don't save if invalid + if (string.IsNullOrWhiteSpace(itemValue)) + { + continue; + } + statement.Reset(); statement.TryBind("@ItemId", itemId.ToGuidParamValue()); statement.TryBind("@Type", pair.Item1); - statement.TryBind("@Value", pair.Item2); + statement.TryBind("@Value", itemValue); if (pair.Item2 == null) { diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index d773fbbf73..7ee0c566f7 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -312,8 +312,8 @@ <HintPath>..\packages\Emby.XmlTv.1.0.3\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath> <Private>True</Private> </Reference> - <Reference Include="MediaBrowser.Naming, Version=1.0.6178.4191, Culture=neutral, processorArchitecture=MSIL"> - <HintPath>..\packages\MediaBrowser.Naming.1.0.3\lib\portable-net45+win8\MediaBrowser.Naming.dll</HintPath> + <Reference Include="MediaBrowser.Naming, Version=1.0.6201.24431, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\packages\MediaBrowser.Naming.1.0.4\lib\portable-net45+win8\MediaBrowser.Naming.dll</HintPath> <Private>True</Private> </Reference> <Reference Include="SQLitePCL.pretty, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> @@ -424,6 +424,9 @@ <ItemGroup> <EmbeddedResource Include="Localization\Ratings\us.txt" /> </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Localization\Ratings\uk.txt" /> + </ItemGroup> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. diff --git a/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs index 38708648fe..561f5ee12e 100644 --- a/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs @@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.EntryPoints if (_appHost.HasPendingRestart) { - _timer = _timerFactory.Create(TimerCallback, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10)); + _timer = _timerFactory.Create(TimerCallback, null, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15)); } } @@ -65,6 +65,8 @@ namespace Emby.Server.Implementations.EntryPoints { DisposeTimer(); + _logger.Info("Automatically restarting the system because it is idle and a restart is required."); + try { _appHost.Restart(); diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 0e1f5a5517..322cdf4f0c 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -91,16 +91,12 @@ namespace Emby.Server.Implementations.HttpServer readonly Dictionary<Type, int> _mapExceptionToStatusCode = new Dictionary<Type, int> { - {typeof (InvalidOperationException), 500}, - {typeof (NotImplementedException), 500}, {typeof (ResourceNotFoundException), 404}, {typeof (FileNotFoundException), 404}, //{typeof (DirectoryNotFoundException), 404}, {typeof (SecurityException), 401}, {typeof (PaymentRequiredException), 402}, - {typeof (UnauthorizedAccessException), 500}, - {typeof (PlatformNotSupportedException), 500}, - {typeof (NotSupportedException), 500} + {typeof (ArgumentException), 400} }; public override void Configure() @@ -228,11 +224,30 @@ namespace Emby.Server.Implementations.HttpServer } } - private void ErrorHandler(Exception ex, IRequest httpReq) + private int GetStatusCode(Exception ex) + { + if (ex is ArgumentException) + { + return 400; + } + + int statusCode; + if (!_mapExceptionToStatusCode.TryGetValue(ex.GetType(), out statusCode)) + { + statusCode = 500; + } + + return statusCode; + } + + private void ErrorHandler(Exception ex, IRequest httpReq, bool logException = true) { try { - _logger.ErrorException("Error processing request", ex); + if (logException) + { + _logger.ErrorException("Error processing request", ex); + } var httpRes = httpReq.Response; @@ -241,11 +256,7 @@ namespace Emby.Server.Implementations.HttpServer return; } - int statusCode; - if (!_mapExceptionToStatusCode.TryGetValue(ex.GetType(), out statusCode)) - { - statusCode = 500; - } + var statusCode = GetStatusCode(ex); httpRes.StatusCode = statusCode; httpRes.ContentType = "text/html"; @@ -264,7 +275,9 @@ namespace Emby.Server.Implementations.HttpServer { if (_listener != null) { + _logger.Info("Stopping HttpListener..."); _listener.Stop(); + _logger.Info("HttpListener stopped"); } } @@ -529,6 +542,10 @@ namespace Emby.Server.Implementations.HttpServer ErrorHandler(new FileNotFoundException(), httpReq); } } + catch (OperationCanceledException ex) + { + ErrorHandler(ex, httpReq, false); + } catch (Exception ex) { ErrorHandler(ex, httpReq); @@ -698,19 +715,19 @@ namespace Emby.Server.Implementations.HttpServer protected virtual void Dispose(bool disposing) { if (_disposed) return; + base.Dispose(); lock (_disposeLock) { if (_disposed) return; + _disposed = true; + if (disposing) { Stop(); } - - //release unmanaged resources here... - _disposed = true; } } diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 995dc7b7b0..e78446bc84 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -203,20 +203,12 @@ namespace Emby.Server.Implementations.HttpServer // Do not use the memoryStreamFactory here, they don't place nice with compression using (var ms = new MemoryStream()) { - using (var compressionStream = GetCompressionStream(ms, compressionType)) - { - ContentTypes.Instance.SerializeToStream(request, dto, compressionStream); - compressionStream.Dispose(); - - var compressedBytes = ms.ToArray(); + ContentTypes.Instance.SerializeToStream(request, dto, ms); + ms.Position = 0; - var httpResult = new StreamWriter(compressedBytes, request.ResponseContentType, _logger); + var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - //httpResult.Headers["Content-Length"] = compressedBytes.Length.ToString(UsCulture); - httpResult.Headers["Content-Encoding"] = compressionType; - - return httpResult; - } + return GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result; } } @@ -591,45 +583,53 @@ namespace Emby.Server.Implementations.HttpServer }; } - string content; - using (var stream = await factoryFn().ConfigureAwait(false)) { - using (var reader = new StreamReader(stream)) + return await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false); + } + } + + private async Task<IHasHeaders> GetCompressedResult(Stream stream, + string requestedCompressionType, + IDictionary<string,string> responseHeaders, + bool isHeadRequest, + string contentType) + { + using (var reader = new MemoryStream()) + { + await stream.CopyToAsync(reader).ConfigureAwait(false); + + reader.Position = 0; + var content = reader.ToArray(); + + if (content.Length >= 1024) { - content = await reader.ReadToEndAsync().ConfigureAwait(false); + content = Compress(content, requestedCompressionType); + responseHeaders["Content-Encoding"] = requestedCompressionType; } - } - var contents = Compress(content, requestedCompressionType); + responseHeaders["Content-Length"] = content.Length.ToString(UsCulture); - responseHeaders["Content-Length"] = contents.Length.ToString(UsCulture); - responseHeaders["Content-Encoding"] = requestedCompressionType; + if (isHeadRequest) + { + return GetHttpResult(new byte[] { }, contentType, true); + } - if (isHeadRequest) - { - return GetHttpResult(new byte[] { }, contentType, true); + return GetHttpResult(content, contentType, true, responseHeaders); } - - return GetHttpResult(contents, contentType, true, responseHeaders); } - private byte[] Compress(string text, string compressionType) + private byte[] Compress(byte[] bytes, string compressionType) { if (compressionType == "deflate") - return Deflate(text); + return Deflate(bytes); if (compressionType == "gzip") - return GZip(text); + return GZip(bytes); throw new NotSupportedException(compressionType); } - private byte[] Deflate(string text) - { - return Deflate(Encoding.UTF8.GetBytes(text)); - } - private byte[] Deflate(byte[] bytes) { // In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream @@ -644,11 +644,6 @@ namespace Emby.Server.Implementations.HttpServer } } - private byte[] GZip(string text) - { - return GZip(Encoding.UTF8.GetBytes(text)); - } - private byte[] GZip(byte[] buffer) { using (var ms = new MemoryStream()) diff --git a/Emby.Server.Implementations/HttpServer/IHttpListener.cs b/Emby.Server.Implementations/HttpServer/IHttpListener.cs index 9f96a8e49d..18df5682d7 100644 --- a/Emby.Server.Implementations/HttpServer/IHttpListener.cs +++ b/Emby.Server.Implementations/HttpServer/IHttpListener.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.HttpServer /// Gets or sets the error handler. /// </summary> /// <value>The error handler.</value> - Action<Exception, IRequest> ErrorHandler { get; set; } + Action<Exception, IRequest, bool> ErrorHandler { get; set; } /// <summary> /// Gets or sets the request handler. diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index 4606d0e316..652fc4f837 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs @@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp _httpRequestFactory = httpRequestFactory; } - public Action<Exception, IRequest> ErrorHandler { get; set; } + public Action<Exception, IRequest, bool> ErrorHandler { get; set; } public Func<IHttpRequest, Uri, Task> RequestHandler { get; set; } public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; } @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp _logger.ErrorException("Error processing request", ex); httpReq = httpReq ?? GetRequest(context); - ErrorHandler(ex, httpReq); + ErrorHandler(ex, httpReq, true); return Task.FromResult(true); } diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index 2e69cd2efa..d782f5b888 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -9,6 +9,7 @@ using System.Linq; using MediaBrowser.Common.IO; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; namespace Emby.Server.Implementations.Library { @@ -19,6 +20,7 @@ namespace Emby.Server.Implementations.Library { private readonly IFileSystem _fileSystem; private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; /// <summary> /// Any folder named in this list will be ignored - can be added to at runtime for extensibility @@ -40,10 +42,11 @@ namespace Emby.Server.Implementations.Library }; - public CoreResolutionIgnoreRule(IFileSystem fileSystem, ILibraryManager libraryManager) + public CoreResolutionIgnoreRule(IFileSystem fileSystem, ILibraryManager libraryManager, ILogger logger) { _fileSystem = fileSystem; _libraryManager = libraryManager; + _logger = logger; } /// <summary> @@ -54,6 +57,12 @@ namespace Emby.Server.Implementations.Library /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent) { + // Don't ignore top level folders + if (fileInfo.IsDirectory && parent is AggregateFolder) + { + return false; + } + var filename = fileInfo.Name; var isHidden = fileInfo.IsHidden; var path = fileInfo.FullName; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 5bf53fcb43..4c788a2abe 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -3084,7 +3084,11 @@ namespace Emby.Server.Implementations.Library foreach (var contentType in ConfigurationManager.Configuration.ContentTypes) { - if (string.Equals(path, contentType.Name, StringComparison.OrdinalIgnoreCase) + if (string.IsNullOrWhiteSpace(contentType.Name)) + { + removeList.Add(contentType); + } + else if (string.Equals(path, contentType.Name, StringComparison.OrdinalIgnoreCase) || _fileSystem.ContainsSubPath(path, contentType.Name)) { removeList.Add(contentType); diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 55a63b4e5d..b791311f9f 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -74,21 +74,21 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return ResolveVideos<MusicVideo>(parent, files, directoryService, false); + return ResolveVideos<MusicVideo>(parent, files, directoryService, false, collectionType); } if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) || string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase)) { - return ResolveVideos<Video>(parent, files, directoryService, false); + return ResolveVideos<Video>(parent, files, directoryService, false, collectionType); } - if (string.IsNullOrEmpty(collectionType)) + if (string.IsNullOrWhiteSpace(collectionType)) { // Owned items should just use the plain video type if (parent == null) { - return ResolveVideos<Video>(parent, files, directoryService, false); + return ResolveVideos<Video>(parent, files, directoryService, false, collectionType); } if (parent is Series || parent.GetParents().OfType<Series>().Any()) @@ -96,18 +96,18 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies return null; } - return ResolveVideos<Movie>(parent, files, directoryService, false); + return ResolveVideos<Movie>(parent, files, directoryService, false, collectionType); } if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) { - return ResolveVideos<Movie>(parent, files, directoryService, true); + return ResolveVideos<Movie>(parent, files, directoryService, true, collectionType); } return null; } - private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions) + private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions, string collectionType) where T : Video, new() { var files = new List<FileSystemMetadata>(); @@ -117,6 +117,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies // Loop through each child file/folder and see if we find a video foreach (var child in fileSystemEntries) { + // This is a hack but currently no better way to resolve a sometimes ambiguous situation + if (string.IsNullOrWhiteSpace(collectionType)) + { + if (string.Equals(child.Name, "tvshow.nfo", StringComparison.OrdinalIgnoreCase) || + string.Equals(child.Name, "season.nfo", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + } + if (child.IsDirectory) { leftOver.Add(child); @@ -408,7 +418,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies !string.Equals(collectionType, CollectionType.Photos) && !string.Equals(collectionType, CollectionType.MusicVideos); - var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion); + var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion, collectionType) ?? + new MultiItemResolverResult(); if (result.Items.Count == 1) { diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 6d527c1cfb..ef440899cb 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -34,7 +34,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var httpRequestOptions = new HttpRequestOptions { Url = mediaSource.Path, - BufferContent = false + BufferContent = false, + + // Some remote urls will expect a user agent to be supplied + UserAgent = "Emby/3.0", + + // Shouldn't matter but may cause issues + EnableHttpCompression = false }; using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false)) diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 04fc78c958..e2446b16ff 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -422,7 +422,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings } var showType = details.showType ?? string.Empty; - + var info = new ProgramInfo { ChannelId = channel, @@ -440,10 +440,23 @@ namespace Emby.Server.Implementations.LiveTv.Listings IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase), IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1, IsMovie = showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1, - ShowId = programInfo.programID, Etag = programInfo.md5 }; + var showId = programInfo.programID ?? string.Empty; + + // According to SchedulesDirect, these are generic, unidentified episodes + // SH005316560000 + var hasUniqueShowId = !showId.StartsWith("SH", StringComparison.OrdinalIgnoreCase) || + !showId.EndsWith("0000", StringComparison.OrdinalIgnoreCase); + + if (!hasUniqueShowId) + { + showId = newID; + } + + info.ShowId = showId; + if (programInfo.videoProperties != null) { info.IsHD = programInfo.videoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase); diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 525db4036d..62a0738c72 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2647,7 +2647,7 @@ namespace Emby.Server.Implementations.LiveTv public GuideInfo GetGuideInfo() { var startDate = DateTime.UtcNow; - var endDate = startDate.AddDays(14); + var endDate = startDate.AddDays(GetGuideDays()); return new GuideInfo { diff --git a/Emby.Server.Implementations/Localization/Ratings/uk.txt b/Emby.Server.Implementations/Localization/Ratings/uk.txt new file mode 100644 index 0000000000..20440921f6 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Ratings/uk.txt @@ -0,0 +1,7 @@ +UK-U,1 +UK-PG,5 +UK-12,7 +UK-12A,7 +UK-15,9 +UK-18,10 +UK-R18,15
\ No newline at end of file diff --git a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs index d758158479..5f37025e2a 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs @@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.ScheduledTasks new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerDaily, - TimeOfDayTicks = TimeSpan.FromHours(1).Ticks, + TimeOfDayTicks = TimeSpan.FromHours(2).Ticks, MaxRuntimeMs = Convert.ToInt32(TimeSpan.FromHours(4).TotalMilliseconds) } }; diff --git a/Emby.Server.Implementations/Sync/CloudSyncProfile.cs b/Emby.Server.Implementations/Sync/CloudSyncProfile.cs index 1a78c8ae66..c0675df817 100644 --- a/Emby.Server.Implementations/Sync/CloudSyncProfile.cs +++ b/Emby.Server.Implementations/Sync/CloudSyncProfile.cs @@ -68,7 +68,7 @@ namespace Emby.Server.Implementations.Sync }, new ProfileCondition { - Condition = ProfileConditionType.EqualsAny, + Condition = ProfileConditionType.Equals, Property = ProfileConditionValue.NumVideoStreams, Value = "1", IsRequired = false @@ -232,20 +232,6 @@ namespace Emby.Server.Implementations.Sync { new ProfileCondition { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2", - IsRequired = true - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioBitrate, - Value = "320000", - IsRequired = true - }, - new ProfileCondition - { Condition = ProfileConditionType.Equals, Property = ProfileConditionValue.IsSecondaryAudio, Value = "false", diff --git a/Emby.Server.Implementations/Sync/SyncJobProcessor.cs b/Emby.Server.Implementations/Sync/SyncJobProcessor.cs index 415757609d..b1adc64df6 100644 --- a/Emby.Server.Implementations/Sync/SyncJobProcessor.cs +++ b/Emby.Server.Implementations/Sync/SyncJobProcessor.cs @@ -515,8 +515,14 @@ namespace Emby.Server.Implementations.Sync jobItem.Progress = 0; - var syncOptions = _config.GetSyncOptions(); var job = _syncManager.GetJob(jobItem.JobId); + if (job == null) + { + _logger.Error("Job not found. Cannot complete the sync job."); + await _syncManager.CancelJobItem(jobItem.Id).ConfigureAwait(false); + return; + } + var user = _userManager.GetUserById(job.UserId); if (user == null) { @@ -552,6 +558,8 @@ namespace Emby.Server.Implementations.Sync } } + var syncOptions = _config.GetSyncOptions(); + var video = item as Video; if (video != null) { diff --git a/Emby.Server.Implementations/Sync/SyncManager.cs b/Emby.Server.Implementations/Sync/SyncManager.cs index 13f60f5eea..310b35afe3 100644 --- a/Emby.Server.Implementations/Sync/SyncManager.cs +++ b/Emby.Server.Implementations/Sync/SyncManager.cs @@ -1030,6 +1030,18 @@ namespace Emby.Server.Implementations.Sync { await CancelJobItem(jobItem.Id).ConfigureAwait(false); } + + var syncJobResult = await GetJobs(new SyncJobQuery + { + ItemId = item, + TargetId = targetId + + }).ConfigureAwait(false); + + foreach (var job in syncJobResult.Items) + { + await CancelJob(job.Id).ConfigureAwait(false); + } } } @@ -1037,15 +1049,7 @@ namespace Emby.Server.Implementations.Sync { var jobItem = _repo.GetJobItem(id); - if (jobItem.Status != SyncJobItemStatus.Queued && jobItem.Status != SyncJobItemStatus.ReadyToTransfer && jobItem.Status != SyncJobItemStatus.Converting && jobItem.Status != SyncJobItemStatus.Failed && jobItem.Status != SyncJobItemStatus.Synced && jobItem.Status != SyncJobItemStatus.Transferring) - { - throw new ArgumentException("Operation is not valid for this job item"); - } - - if (jobItem.Status != SyncJobItemStatus.Synced) - { - jobItem.Status = SyncJobItemStatus.Cancelled; - } + jobItem.Status = SyncJobItemStatus.Cancelled; jobItem.Progress = 0; jobItem.IsMarkedForRemoval = true; @@ -1071,18 +1075,18 @@ namespace Emby.Server.Implementations.Sync _logger.ErrorException("Error deleting directory {0}", ex, path); } - //var jobItemsResult = GetJobItems(new SyncJobItemQuery - //{ - // AddMetadata = false, - // JobId = jobItem.JobId, - // Limit = 0, - // Statuses = new[] { SyncJobItemStatus.Converting, SyncJobItemStatus.Failed, SyncJobItemStatus.Queued, SyncJobItemStatus.ReadyToTransfer, SyncJobItemStatus.Synced, SyncJobItemStatus.Transferring } - //}); + var jobItemsResult = GetJobItems(new SyncJobItemQuery + { + AddMetadata = false, + JobId = jobItem.JobId, + Limit = 0, + Statuses = new[] { SyncJobItemStatus.Converting, SyncJobItemStatus.Queued, SyncJobItemStatus.ReadyToTransfer, SyncJobItemStatus.Synced, SyncJobItemStatus.Transferring } + }); - //if (jobItemsResult.TotalRecordCount == 0) - //{ - // await CancelJob(jobItem.JobId).ConfigureAwait(false); - //} + if (jobItemsResult.TotalRecordCount == 0) + { + await CancelJob(jobItem.JobId).ConfigureAwait(false); + } } public Task MarkJobItemForRemoval(string id) diff --git a/Emby.Server.Implementations/Sync/SyncNotificationEntryPoint.cs b/Emby.Server.Implementations/Sync/SyncNotificationEntryPoint.cs index 46cdb28a4d..06e0e66a91 100644 --- a/Emby.Server.Implementations/Sync/SyncNotificationEntryPoint.cs +++ b/Emby.Server.Implementations/Sync/SyncNotificationEntryPoint.cs @@ -38,6 +38,18 @@ namespace Emby.Server.Implementations.Sync } } + + if (item.Status == SyncJobItemStatus.Cancelled) + { + try + { + await _sessionManager.SendMessageToUserDeviceSessions(item.TargetId, "SyncJobItemCancelled", item, CancellationToken.None).ConfigureAwait(false); + } + catch + { + + } + } } public void Dispose() diff --git a/Emby.Server.Implementations/Sync/SyncRepository.cs b/Emby.Server.Implementations/Sync/SyncRepository.cs index 885f8e64a6..aafce3500f 100644 --- a/Emby.Server.Implementations/Sync/SyncRepository.cs +++ b/Emby.Server.Implementations/Sync/SyncRepository.cs @@ -221,48 +221,70 @@ namespace Emby.Server.Implementations.Sync using (var connection = CreateConnection()) { string commandText; - var paramList = new List<object>(); if (insert) { - commandText = "insert into SyncJobs (Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + commandText = "insert into SyncJobs (Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Profile, @Quality, @Bitrate, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)"; } else { - commandText = "update SyncJobs set TargetId=?,Name=?,Profile=?,Quality=?,Bitrate=?,Status=?,Progress=?,UserId=?,ItemIds=?,Category=?,ParentId=?,UnwatchedOnly=?,ItemLimit=?,SyncNewContent=?,DateCreated=?,DateLastModified=?,ItemCount=? where Id=?"; + commandText = "update SyncJobs set TargetId=@TargetId,Name=@Name,Profile=@Profile,Quality=@Quality,Bitrate=@Bitrate,Status=@Status,Progress=@Progress,UserId=@UserId,ItemIds=@ItemIds,Category=@Category,ParentId=@ParentId,UnwatchedOnly=@UnwatchedOnly,ItemLimit=@ItemLimit,SyncNewContent=@SyncNewContent,DateCreated=@DateCreated,DateLastModified=@DateLastModified,ItemCount=@ItemCount where Id=@Id"; } - paramList.Add(job.TargetId); - paramList.Add(job.Name); - paramList.Add(job.Profile); - paramList.Add(job.Quality); - paramList.Add(job.Bitrate); - paramList.Add(job.Status.ToString()); - paramList.Add(job.Progress); - paramList.Add(job.UserId); + connection.RunInTransaction(conn => + { + using (var statement = PrepareStatementSafe(connection, commandText)) + { + statement.TryBind("@TargetId", job.TargetId); + statement.TryBind("@Name", job.Name); + statement.TryBind("@Profile", job.Profile); + statement.TryBind("@Quality", job.Quality); + statement.TryBind("@Bitrate", job.Bitrate); + statement.TryBind("@Status", job.Status.ToString()); + statement.TryBind("@Progress", job.Progress); + statement.TryBind("@UserId", job.UserId); + + statement.TryBind("@ItemIds", string.Join(",", job.RequestedItemIds.ToArray())); + + if (job.Category.HasValue) + { + statement.TryBind("@Category", job.Category.Value.ToString()); + } + else + { + statement.TryBindNull("@Category"); + } - paramList.Add(string.Join(",", job.RequestedItemIds.ToArray())); - paramList.Add(job.Category); - paramList.Add(job.ParentId); - paramList.Add(job.UnwatchedOnly); - paramList.Add(job.ItemLimit); - paramList.Add(job.SyncNewContent); - paramList.Add(job.DateCreated.ToDateTimeParamValue()); - paramList.Add(job.DateLastModified.ToDateTimeParamValue()); - paramList.Add(job.ItemCount); + if (!string.IsNullOrWhiteSpace(job.ParentId)) + { + statement.TryBind("@ParentId", job.ParentId); + } + else + { + statement.TryBindNull("@ParentId"); + } - if (insert) - { - paramList.Insert(0, job.Id.ToGuidParamValue()); - } - else - { - paramList.Add(job.Id.ToGuidParamValue()); - } + statement.TryBind("@UnwatchedOnly", job.UnwatchedOnly); - connection.RunInTransaction(conn => - { - conn.Execute(commandText, paramList.ToArray()); + if (job.ItemLimit.HasValue) + { + statement.TryBind("@ItemLimit", job.ItemLimit); + } + else + { + statement.TryBindNull("@ItemLimit"); + } + + statement.TryBind("@SyncNewContent", job.SyncNewContent); + + statement.TryBind("@DateCreated", job.DateCreated.ToDateTimeParamValue()); + statement.TryBind("@DateLastModified", job.DateLastModified.ToDateTimeParamValue()); + + statement.TryBind("@ItemCount", job.ItemCount); + statement.TryBind("@Id", job.Id.ToGuidParamValue()); + + statement.MoveNext(); + } }, TransactionMode); } } @@ -338,6 +360,11 @@ namespace Emby.Server.Implementations.Sync whereClauses.Add("UserId=?"); paramList.Add(query.UserId); } + if (!string.IsNullOrWhiteSpace(query.ItemId)) + { + whereClauses.Add("ItemIds like ?"); + paramList.Add("%" + query.ItemId + "%"); + } if (query.SyncNewContent.HasValue) { whereClauses.Add("SyncNewContent=?"); diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs index c15e0ee41b..79a1e46404 100644 --- a/Emby.Server.Implementations/Udp/UdpServer.cs +++ b/Emby.Server.Implementations/Udp/UdpServer.cs @@ -154,6 +154,9 @@ namespace Emby.Server.Implementations.Udp catch (ObjectDisposedException) { } + catch (OperationCanceledException) + { + } catch (Exception ex) { _logger.ErrorException("Error receiving udp message", ex); @@ -167,6 +170,11 @@ namespace Emby.Server.Implementations.Udp /// <param name="message">The message.</param> private void OnMessageReceived(SocketReceiveResult message) { + if (_isDisposed) + { + return; + } + if (message.RemoteEndPoint.Port == 0) { return; @@ -221,6 +229,11 @@ namespace Emby.Server.Implementations.Udp public async Task SendAsync(byte[] bytes, IpEndPointInfo remoteEndPoint) { + if (_isDisposed) + { + throw new ObjectDisposedException(GetType().Name); + } + if (bytes == null) { throw new ArgumentNullException("bytes"); diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config index 09b0af8981..fcce67b330 100644 --- a/Emby.Server.Implementations/packages.config +++ b/Emby.Server.Implementations/packages.config @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <packages> <package id="Emby.XmlTv" version="1.0.3" targetFramework="portable45-net45+win8" /> - <package id="MediaBrowser.Naming" version="1.0.3" targetFramework="portable45-net45+win8" /> + <package id="MediaBrowser.Naming" version="1.0.4" targetFramework="portable45-net45+win8" /> <package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" /> <package id="SQLitePCLRaw.core" version="1.1.1" targetFramework="portable45-net45+win8" /> <package id="UniversalDetector" version="1.0.1" targetFramework="portable45-net45+win8" /> |
