aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs83
-rw-r--r--Emby.Server.Implementations/Connect/ConnectManager.cs4
-rw-r--r--Emby.Server.Implementations/Data/SqliteExtensions.cs12
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs10
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj7
-rw-r--r--Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs4
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs47
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs71
-rw-r--r--Emby.Server.Implementations/HttpServer/IHttpListener.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs4
-rw-r--r--Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs11
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs6
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs27
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs8
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs17
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/uk.txt7
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs2
-rw-r--r--Emby.Server.Implementations/Sync/CloudSyncProfile.cs16
-rw-r--r--Emby.Server.Implementations/Sync/SyncJobProcessor.cs10
-rw-r--r--Emby.Server.Implementations/Sync/SyncManager.cs44
-rw-r--r--Emby.Server.Implementations/Sync/SyncNotificationEntryPoint.cs12
-rw-r--r--Emby.Server.Implementations/Sync/SyncRepository.cs89
-rw-r--r--Emby.Server.Implementations/Udp/UdpServer.cs13
-rw-r--r--Emby.Server.Implementations/packages.config2
25 files changed, 285 insertions, 225 deletions
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index 0df916ded..f7dc93009 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 b7faaa901..8c8b7b026 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 d6ad0ba8a..783258a13 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 8e6a277a4..8c16216b9 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 d773fbbf7..7ee0c566f 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 38708648f..561f5ee12 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 0e1f5a551..322cdf4f0 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 995dc7b7b..e78446bc8 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 9f96a8e49..18df5682d 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 4606d0e31..652fc4f83 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 2e69cd2ef..d782f5b88 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 5bf53fcb4..4c788a2ab 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 55a63b4e5..b791311f9 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 6d527c1cf..ef440899c 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 04fc78c95..e2446b16f 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 525db4036..62a0738c7 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 000000000..20440921f
--- /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 d75815847..5f37025e2 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 1a78c8ae6..c0675df81 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 415757609..b1adc64df 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 13f60f5ee..310b35afe 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 46cdb28a4..06e0e66a9 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 885f8e64a..aafce3500 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 c15e0ee41..79a1e4640 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 09b0af898..fcce67b33 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" />