diff --git a/Emby.Drawing/GDI/DynamicImageHelpers.cs b/Emby.Drawing/GDI/DynamicImageHelpers.cs
index 7b8ef2f98a..59340af8a9 100644
--- a/Emby.Drawing/GDI/DynamicImageHelpers.cs
+++ b/Emby.Drawing/GDI/DynamicImageHelpers.cs
@@ -33,7 +33,9 @@ namespace Emby.Drawing.GDI
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
- graphics.CompositingMode = CompositingMode.SourceCopy;
+
+ // SourceCopy causes the image to be blank in OSX
+ //graphics.CompositingMode = CompositingMode.SourceCopy;
for (var row = 0; row < rows; row++)
{
@@ -44,19 +46,9 @@ namespace Emby.Drawing.GDI
if (files.Count > index)
{
- using (var fileStream = fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
+ using (var imgtemp = Image.FromFile(files[index]))
{
- using (var memoryStream = new MemoryStream())
- {
- fileStream.CopyTo(memoryStream);
-
- memoryStream.Position = 0;
-
- using (var imgtemp = Image.FromStream(memoryStream, true, false))
- {
- graphics.DrawImage(imgtemp, x, y, cellWidth, cellHeight);
- }
- }
+ graphics.DrawImage(imgtemp, x, y, cellWidth, cellHeight);
}
}
@@ -90,7 +82,9 @@ namespace Emby.Drawing.GDI
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
- graphics.CompositingMode = CompositingMode.SourceCopy;
+
+ // SourceCopy causes the image to be blank in OSX
+ //graphics.CompositingMode = CompositingMode.SourceCopy;
for (var row = 0; row < rows; row++)
{
@@ -99,21 +93,10 @@ namespace Emby.Drawing.GDI
var x = col * singleSize;
var y = row * singleSize;
- using (var fileStream = fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
+ using (var imgtemp = Image.FromFile(files[index]))
{
- using (var memoryStream = new MemoryStream())
- {
- fileStream.CopyTo(memoryStream);
-
- memoryStream.Position = 0;
-
- using (var imgtemp = Image.FromStream(memoryStream, true, false))
- {
- graphics.DrawImage(imgtemp, x, y, singleSize, singleSize);
- }
- }
+ graphics.DrawImage(imgtemp, x, y, singleSize, singleSize);
}
-
index++;
}
}
@@ -121,16 +104,5 @@ namespace Emby.Drawing.GDI
}
}
}
-
- private static Stream GetStream(Image image)
- {
- var ms = new MemoryStream();
-
- image.Save(ms, ImageFormat.Png);
-
- ms.Position = 0;
-
- return ms;
- }
}
}
diff --git a/Emby.Drawing/GDI/GDIImageEncoder.cs b/Emby.Drawing/GDI/GDIImageEncoder.cs
index bdd1c5a22f..afd16899dc 100644
--- a/Emby.Drawing/GDI/GDIImageEncoder.cs
+++ b/Emby.Drawing/GDI/GDIImageEncoder.cs
@@ -119,9 +119,11 @@ namespace Emby.Drawing.GDI
thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
- thumbnailGraph.CompositingMode = !hasPostProcessing ?
- CompositingMode.SourceCopy :
- CompositingMode.SourceOver;
+
+ // SourceCopy causes the image to be blank in OSX
+ //thumbnailGraph.CompositingMode = !hasPostProcessing ?
+ // CompositingMode.SourceCopy :
+ // CompositingMode.SourceOver;
SetBackgroundColor(thumbnailGraph, options);
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index dc811812ae..7c5f7cde40 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -63,6 +63,15 @@ namespace MediaBrowser.Api
Instance = this;
_sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress;
+ _sessionManager.PlaybackStart += _sessionManager_PlaybackStart;
+ }
+
+ private void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e)
+ {
+ if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
+ {
+ PingTranscodingJob(e.PlaySessionId, e.IsPaused);
+ }
}
void _sessionManager_PlaybackProgress(object sender, PlaybackProgressEventArgs e)
@@ -126,9 +135,10 @@ namespace MediaBrowser.Api
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool dispose)
{
- var jobCount = _activeTranscodingJobs.Count;
+ var list = _activeTranscodingJobs.ToList();
+ var jobCount = list.Count;
- Parallel.ForEach(_activeTranscodingJobs.ToList(), j => KillTranscodingJob(j, false, path => true));
+ Parallel.ForEach(list, j => KillTranscodingJob(j, false, path => true));
// Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
if (jobCount > 0)
@@ -182,13 +192,13 @@ namespace MediaBrowser.Api
_activeTranscodingJobs.Add(job);
- ReportTranscodingProgress(job, state, null, null, null, null);
+ ReportTranscodingProgress(job, state, null, null, null, null, null);
return job;
}
}
- public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded)
+ public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
{
var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;
@@ -198,6 +208,7 @@ namespace MediaBrowser.Api
job.CompletionPercentage = percentComplete;
job.TranscodingPositionTicks = ticks;
job.BytesTranscoded = bytesTranscoded;
+ job.BitRate = bitRate;
}
var deviceId = state.Request.DeviceId;
@@ -209,7 +220,7 @@ namespace MediaBrowser.Api
_sessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo
{
- Bitrate = state.TotalOutputBitrate,
+ Bitrate = bitRate ?? state.TotalOutputBitrate,
AudioCodec = audioCodec,
VideoCodec = videoCodec,
Container = state.OutputContainer,
@@ -348,7 +359,7 @@ namespace MediaBrowser.Api
return;
}
- var timerDuration = 1000;
+ var timerDuration = 10000;
if (job.Type != TranscodingJobType.Progressive)
{
@@ -400,7 +411,7 @@ namespace MediaBrowser.Api
}
}
- Logger.Debug("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
+ Logger.Info("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
KillTranscodingJob(job, true, path => true);
}
@@ -558,13 +569,13 @@ namespace MediaBrowser.Api
{
}
- catch (IOException ex)
+ catch (IOException)
{
//Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
DeletePartialStreamFiles(path, jobType, retryCount + 1, 500);
}
- catch (Exception ex)
+ catch
{
//Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
}
@@ -684,6 +695,7 @@ namespace MediaBrowser.Api
public long? BytesDownloaded { get; set; }
public long? BytesTranscoded { get; set; }
+ public int? BitRate { get; set; }
public long? TranscodingPositionTicks { get; set; }
public long? DownloadPositionTicks { get; set; }
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 44a367be09..3ff432d741 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -139,6 +139,10 @@ namespace MediaBrowser.Api
{
options.ImageTypeLimit = hasDtoOptions.ImageTypeLimit.Value;
}
+ if (hasDtoOptions.EnableUserData.HasValue)
+ {
+ options.EnableUserData = hasDtoOptions.EnableUserData.Value;
+ }
if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
{
diff --git a/MediaBrowser.Api/IHasDtoOptions.cs b/MediaBrowser.Api/IHasDtoOptions.cs
index dac366113c..6ed1670c21 100644
--- a/MediaBrowser.Api/IHasDtoOptions.cs
+++ b/MediaBrowser.Api/IHasDtoOptions.cs
@@ -4,6 +4,7 @@ namespace MediaBrowser.Api
public interface IHasDtoOptions : IHasItemFields
{
bool? EnableImages { get; set; }
+ bool? EnableUserData { get; set; }
int? ImageTypeLimit { get; set; }
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 5866ad15bc..3280358dfa 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -573,11 +573,9 @@ namespace MediaBrowser.Api.Images
var outputFormats = GetOutputFormats(request, imageInfo, cropwhitespace, supportedImageEnhancers);
- var cacheGuid = new Guid(_imageProcessor.GetImageCacheTag(item, imageInfo, supportedImageEnhancers));
-
TimeSpan? cacheDuration = null;
- if (!string.IsNullOrEmpty(request.Tag) && cacheGuid == new Guid(request.Tag))
+ if (!string.IsNullOrEmpty(request.Tag))
{
cacheDuration = TimeSpan.FromDays(365);
}
diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs
index 5aab15dff1..a918e841fb 100644
--- a/MediaBrowser.Api/ItemRefreshService.cs
+++ b/MediaBrowser.Api/ItemRefreshService.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Providers;
using ServiceStack;
using System.Threading;
using CommonIO;
+using MediaBrowser.Model.Logging;
namespace MediaBrowser.Api
{
@@ -39,12 +40,14 @@ namespace MediaBrowser.Api
private readonly ILibraryManager _libraryManager;
private readonly IProviderManager _providerManager;
private readonly IFileSystem _fileSystem;
+ private readonly ILogger _logger;
- public ItemRefreshService(ILibraryManager libraryManager, IProviderManager providerManager, IFileSystem fileSystem)
+ public ItemRefreshService(ILibraryManager libraryManager, IProviderManager providerManager, IFileSystem fileSystem, ILogger logger)
{
_libraryManager = libraryManager;
_providerManager = providerManager;
_fileSystem = fileSystem;
+ _logger = logger;
}
///
@@ -69,7 +72,7 @@ namespace MediaBrowser.Api
private MetadataRefreshOptions GetRefreshOptions(BaseRefreshRequest request)
{
- return new MetadataRefreshOptions(new DirectoryService(_fileSystem))
+ return new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
{
MetadataRefreshMode = request.MetadataRefreshMode,
ImageRefreshMode = request.ImageRefreshMode,
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index b944a39b6a..2778cfe29c 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -304,7 +304,7 @@ namespace MediaBrowser.Api
item.EndDate = request.EndDate.HasValue ? NormalizeDateTime(request.EndDate.Value) : (DateTime?)null;
item.PremiereDate = request.PremiereDate.HasValue ? NormalizeDateTime(request.PremiereDate.Value) : (DateTime?)null;
item.ProductionYear = request.ProductionYear;
- item.OfficialRating = request.OfficialRating;
+ item.OfficialRating = string.IsNullOrWhiteSpace(request.OfficialRating) ? null : request.OfficialRating;
item.CustomRating = request.CustomRating;
SetProductionLocations(item, request);
diff --git a/MediaBrowser.Api/Library/FileOrganizationService.cs b/MediaBrowser.Api/Library/FileOrganizationService.cs
index 0ed08a8607..ca391bef08 100644
--- a/MediaBrowser.Api/Library/FileOrganizationService.cs
+++ b/MediaBrowser.Api/Library/FileOrganizationService.cs
@@ -154,9 +154,12 @@ namespace MediaBrowser.Api.Library
public void Post(PerformOrganization request)
{
+ // Don't await this
var task = _iFileOrganizationService.PerformOrganization(request.Id);
- Task.WaitAll(task);
+ // Async processing (close dialog early instead of waiting until the file has been copied)
+ // Wait 2s for exceptions that may occur to have them forwarded to the client for immediate error display
+ task.Wait(2000);
}
public void Post(OrganizeEpisode request)
@@ -168,6 +171,7 @@ namespace MediaBrowser.Api.Library
dicNewProviderIds = request.NewSeriesProviderIds;
}
+ // Don't await this
var task = _iFileOrganizationService.PerformEpisodeOrganization(new EpisodeFileOrganizationRequest
{
EndingEpisodeNumber = request.EndingEpisodeNumber,
@@ -182,11 +186,9 @@ namespace MediaBrowser.Api.Library
TargetFolder = request.TargetFolder
});
- // For async processing (close dialog early instead of waiting until the file has been copied)
- //var tasks = new Task[] { task };
- //Task.WaitAll(tasks, 8000);
-
- Task.WaitAll(task);
+ // Async processing (close dialog early instead of waiting until the file has been copied)
+ // Wait 2s for exceptions that may occur to have them forwarded to the client for immediate error display
+ task.Wait(2000);
}
public object Get(GetSmartMatchInfos request)
diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs
index 3cf0d5d937..72966a7cdc 100644
--- a/MediaBrowser.Api/Library/LibraryStructureService.cs
+++ b/MediaBrowser.Api/Library/LibraryStructureService.cs
@@ -10,6 +10,9 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Api.Library
{
@@ -52,6 +55,8 @@ namespace MediaBrowser.Api.Library
///
/// The path.
public string[] Paths { get; set; }
+
+ public LibraryOptions LibraryOptions { get; set; }
}
[Route("/Library/VirtualFolders", "DELETE")]
@@ -136,6 +141,14 @@ namespace MediaBrowser.Api.Library
public bool RefreshLibrary { get; set; }
}
+ [Route("/Library/VirtualFolders/LibraryOptions", "POST")]
+ public class UpdateLibraryOptions : IReturnVoid
+ {
+ public string Id { get; set; }
+
+ public LibraryOptions LibraryOptions { get; set; }
+ }
+
///
/// Class LibraryStructureService
///
@@ -184,13 +197,22 @@ namespace MediaBrowser.Api.Library
return ToOptimizedSerializedResultUsingCache(result);
}
+ public void Post(UpdateLibraryOptions request)
+ {
+ var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(request.Id);
+
+ collectionFolder.UpdateLibraryOptions(request.LibraryOptions);
+ }
+
///
/// Posts the specified request.
///
/// The request.
public void Post(AddVirtualFolder request)
{
- _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, request.Paths, request.RefreshLibrary);
+ var libraryOptions = request.LibraryOptions ?? new LibraryOptions();
+
+ _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, request.Paths, libraryOptions, request.RefreshLibrary);
}
///
@@ -214,12 +236,12 @@ namespace MediaBrowser.Api.Library
var currentPath = Path.Combine(rootFolderPath, request.Name);
var newPath = Path.Combine(rootFolderPath, request.NewName);
- if (!_fileSystem.DirectoryExists(currentPath))
+ if (!_fileSystem.DirectoryExists(currentPath))
{
throw new DirectoryNotFoundException("The media collection does not exist");
}
- if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && _fileSystem.DirectoryExists(newPath))
+ if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && _fileSystem.DirectoryExists(newPath))
{
throw new ArgumentException("There is already a media collection with the name " + newPath + ".");
}
@@ -234,11 +256,11 @@ namespace MediaBrowser.Api.Library
//Create an unique name
var temporaryName = Guid.NewGuid().ToString();
var temporaryPath = Path.Combine(rootFolderPath, temporaryName);
- _fileSystem.MoveDirectory(currentPath, temporaryPath);
+ _fileSystem.MoveDirectory(currentPath, temporaryPath);
currentPath = temporaryPath;
}
- _fileSystem.MoveDirectory(currentPath, newPath);
+ _fileSystem.MoveDirectory(currentPath, newPath);
}
finally
{
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index c687758b72..545ac162ff 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -82,6 +82,9 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "AddCurrentProgram", Description = "Optional. Adds current program info to each channel", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public bool AddCurrentProgram { get; set; }
+ [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+ public bool? EnableUserData { get; set; }
+
public GetChannels()
{
AddCurrentProgram = true;
@@ -149,6 +152,9 @@ namespace MediaBrowser.Api.LiveTv
public bool EnableTotalRecordCount { get; set; }
+ [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+ public bool? EnableUserData { get; set; }
+
public GetRecordings()
{
EnableTotalRecordCount = true;
@@ -271,6 +277,9 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string EnableImageTypes { get; set; }
+ [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+ public bool? EnableUserData { get; set; }
+
///
/// Fields to return within the items, in addition to basic information
///
@@ -331,6 +340,9 @@ namespace MediaBrowser.Api.LiveTv
/// The fields.
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string Fields { get; set; }
+
+ [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+ public bool? EnableUserData { get; set; }
}
[Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")]
@@ -726,7 +738,12 @@ namespace MediaBrowser.Api.LiveTv
var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
- var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, GetDtoOptions(Request), user).ConfigureAwait(false)).ToArray();
+ var options = GetDtoOptions(request);
+ RemoveFields(options);
+
+ options.AddCurrentProgram = request.AddCurrentProgram;
+
+ var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user).ConfigureAwait(false)).ToArray();
var result = new QueryResult
{
@@ -737,6 +754,14 @@ namespace MediaBrowser.Api.LiveTv
return ToOptimizedSerializedResultUsingCache(result);
}
+ private void RemoveFields(DtoOptions options)
+ {
+ options.Fields.Remove(ItemFields.CanDelete);
+ options.Fields.Remove(ItemFields.CanDownload);
+ options.Fields.Remove(ItemFields.DisplayPreferencesId);
+ options.Fields.Remove(ItemFields.Etag);
+ }
+
public object Get(GetChannel request)
{
var user = string.IsNullOrWhiteSpace(request.UserId) ? null : _userManager.GetUserById(request.UserId);
@@ -997,10 +1022,7 @@ namespace MediaBrowser.Api.LiveTv
public async Task