diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
index b8300ac979..7779c2fc5d 100644
--- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
+++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
@@ -155,6 +155,7 @@ namespace Emby.Drawing.ImageMagick
AutoOrientImage(originalImage);
}
+ AddForegroundLayer(originalImage, options);
DrawIndicator(originalImage, width, height, options);
originalImage.CurrentImage.CompressionQuality = quality;
@@ -177,6 +178,8 @@ namespace Emby.Drawing.ImageMagick
}
wand.CurrentImage.CompositeImage(originalImage, CompositeOperator.OverCompositeOp, 0, 0);
+
+ AddForegroundLayer(wand, options);
DrawIndicator(wand, width, height, options);
wand.CurrentImage.CompressionQuality = quality;
@@ -189,6 +192,16 @@ namespace Emby.Drawing.ImageMagick
SaveDelay();
}
+ private void AddForegroundLayer(MagickWand wand, ImageProcessingOptions options)
+ {
+ if (string.IsNullOrWhiteSpace(options.ForegroundLayer))
+ {
+ return;
+ }
+
+ // TODO
+ }
+
private void AutoOrientImage(MagickWand wand)
{
wand.CurrentImage.AutoOrientImage();
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index e016127004..89e2649b53 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -234,7 +234,7 @@ namespace Emby.Drawing
var quality = options.Quality;
var outputFormat = GetOutputFormat(options.SupportedOutputFormats[0]);
- var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor);
+ var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor, options.ForegroundLayer);
var semaphore = GetLock(cacheFilePath);
@@ -473,7 +473,7 @@ namespace Emby.Drawing
///
/// Gets the cache file path based on a set of parameters
///
- private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
+ private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor, string foregroundLayer)
{
var filename = originalPath;
@@ -507,6 +507,11 @@ namespace Emby.Drawing
filename += "b=" + backgroundColor;
}
+ if (!string.IsNullOrEmpty(foregroundLayer))
+ {
+ filename += "fl=" + foregroundLayer;
+ }
+
filename += "v=" + Version;
return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLower());
diff --git a/MediaBrowser.Api/Images/ImageRequest.cs b/MediaBrowser.Api/Images/ImageRequest.cs
index cdd348bb52..8b86ee7e0f 100644
--- a/MediaBrowser.Api/Images/ImageRequest.cs
+++ b/MediaBrowser.Api/Images/ImageRequest.cs
@@ -66,7 +66,10 @@ namespace MediaBrowser.Api.Images
[ApiMember(Name = "BackgroundColor", Description = "Optional. Apply a background color for transparent images.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string BackgroundColor { get; set; }
-
+
+ [ApiMember(Name = "ForegroundLayer", Description = "Optional. Apply a foreground layer on top of the image.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ForegroundLayer { get; set; }
+
public ImageRequest()
{
EnableImageEnhancers = true;
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 7122c8fc12..8d58070fdf 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -624,6 +624,7 @@ namespace MediaBrowser.Api.Images
PercentPlayed = request.PercentPlayed ?? 0,
UnplayedCount = request.UnplayedCount,
BackgroundColor = request.BackgroundColor,
+ ForegroundLayer = request.ForegroundLayer,
SupportedOutputFormats = supportedFormats
};
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 00caa74d62..f66363da67 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -477,7 +477,7 @@ namespace MediaBrowser.Api.Playback
var pts = string.Empty;
- if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
+ if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && !state.VideoRequest.CopyTimestamps)
{
var seconds = TimeSpan.FromTicks(state.Request.StartTimeTicks ?? 0).TotalSeconds;
@@ -604,6 +604,10 @@ namespace MediaBrowser.Api.Playback
{
var seconds = Math.Round(TimeSpan.FromTicks(state.Request.StartTimeTicks ?? 0).TotalSeconds);
+ var setPtsParam = state.VideoRequest.CopyTimestamps
+ ? string.Empty
+ : string.Format(",setpts=PTS -{0}/TB", seconds.ToString(UsCulture));
+
if (state.SubtitleStream.IsExternal)
{
var subtitlePath = state.SubtitleStream.Path;
@@ -621,18 +625,18 @@ namespace MediaBrowser.Api.Playback
}
// TODO: Perhaps also use original_size=1920x800 ??
- return string.Format("subtitles=filename='{0}'{1},setpts=PTS -{2}/TB",
+ return string.Format("subtitles=filename='{0}'{1}{2}",
MediaEncoder.EscapeSubtitleFilterPath(subtitlePath),
charsetParam,
- seconds.ToString(UsCulture));
+ setPtsParam);
}
var mediaPath = state.MediaPath ?? string.Empty;
- return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB",
+ return string.Format("subtitles='{0}:si={1}'{2}",
MediaEncoder.EscapeSubtitleFilterPath(mediaPath),
state.InternalSubtitleStreamOffset.ToString(UsCulture),
- seconds.ToString(UsCulture));
+ setPtsParam);
}
///
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index 50aa2df19c..0af419cf33 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -65,7 +65,8 @@ namespace MediaBrowser.Api.Playback.Progressive
///
public class VideoService : BaseProgressiveStreamingService
{
- public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
+ public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient)
+ : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
{
}
@@ -137,11 +138,6 @@ namespace MediaBrowser.Api.Playback.Progressive
var isOutputMkv = string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase);
- if (state.RunTimeTicks.HasValue && state.VideoRequest.CopyTimestamps)
- {
- args += " -copyts -avoid_negative_ts disabled -start_at_zero";
- }
-
if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
if (state.VideoStream != null && IsH264(state.VideoStream) &&
@@ -160,10 +156,22 @@ namespace MediaBrowser.Api.Playback.Progressive
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
+ var hasCopyTs = false;
// Add resolution params, if specified
if (!hasGraphicalSubs)
{
- args += GetOutputSizeParam(state, videoCodec);
+ var outputSizeParam = GetOutputSizeParam(state, videoCodec);
+ args += outputSizeParam;
+ hasCopyTs = outputSizeParam.IndexOf("copyts", StringComparison.OrdinalIgnoreCase) != -1;
+ }
+
+ if (state.RunTimeTicks.HasValue && state.VideoRequest.CopyTimestamps)
+ {
+ if (!hasCopyTs)
+ {
+ args += " -copyts";
+ }
+ args += " -avoid_negative_ts disabled -start_at_zero";
}
var qualityParam = GetVideoQualityParam(state, videoCodec);
diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
index ff11c889a6..1b5e260d71 100644
--- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
+++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Common.Implementations.Networking
Logger = logger;
}
- private volatile List _localIpAddresses;
+ private List _localIpAddresses;
private readonly object _localIpAddressSyncLock = new object();
///
@@ -29,24 +29,20 @@ namespace MediaBrowser.Common.Implementations.Networking
/// IPAddress.
public IEnumerable GetLocalIpAddresses()
{
- const int cacheMinutes = 3;
- var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes;
+ const int cacheMinutes = 5;
- if (_localIpAddresses == null || forceRefresh)
+ lock (_localIpAddressSyncLock)
{
- lock (_localIpAddressSyncLock)
- {
- forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes;
+ var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes;
- if (_localIpAddresses == null || forceRefresh)
- {
- var addresses = GetLocalIpAddressesInternal().ToList();
+ if (_localIpAddresses == null || forceRefresh)
+ {
+ var addresses = GetLocalIpAddressesInternal().ToList();
- _localIpAddresses = addresses;
- _lastRefresh = DateTime.UtcNow;
+ _localIpAddresses = addresses;
+ _lastRefresh = DateTime.UtcNow;
- return addresses;
- }
+ return addresses;
}
}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index a4ccbb6f84..8d727a1128 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -103,7 +103,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
Logger = logger;
_fileSystem = fileSystem;
- ReloadTriggerEvents(true);
+ InitTriggerEvents();
}
///
@@ -233,11 +233,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
///
/// The _triggers
///
- private volatile List _triggers;
- ///
- /// The _triggers sync lock
- ///
- private readonly object _triggersSyncLock = new object();
+ private List _triggers;
///
/// Gets the triggers that define when the task will run
///
@@ -247,17 +243,6 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
get
{
- if (_triggers == null)
- {
- lock (_triggersSyncLock)
- {
- if (_triggers == null)
- {
- _triggers = LoadTriggers();
- }
- }
- }
-
return _triggers;
}
set
@@ -303,6 +288,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
}
}
+ private void InitTriggerEvents()
+ {
+ _triggers = LoadTriggers();
+ ReloadTriggerEvents(true);
+ }
+
public void ReloadTriggerEvents()
{
ReloadTriggerEvents(false);
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index 2b80b701e0..3fd8d84dd5 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -39,6 +39,7 @@ namespace MediaBrowser.Controller.Drawing
public double PercentPlayed { get; set; }
public string BackgroundColor { get; set; }
+ public string ForegroundLayer { get; set; }
public bool HasDefaultOptions(string originalImagePath)
{
@@ -83,7 +84,8 @@ namespace MediaBrowser.Controller.Drawing
!AddPlayedIndicator &&
PercentPlayed.Equals(0) &&
!UnplayedCount.HasValue &&
- string.IsNullOrEmpty(BackgroundColor);
+ string.IsNullOrEmpty(BackgroundColor) &&
+ string.IsNullOrEmpty(ForegroundLayer);
}
private bool IsFormatSupported(string originalImagePath)
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index 095fa95e10..50c41fd217 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -31,6 +31,7 @@ namespace MediaBrowser.Model.LiveTv
public string Type { get; set; }
public bool ImportFavoritesOnly { get; set; }
public bool IsEnabled { get; set; }
+ public string GuideGroup { get; set; }
public TunerHostInfo()
{
@@ -48,5 +49,6 @@ namespace MediaBrowser.Model.LiveTv
public string ZipCode { get; set; }
public string Country { get; set; }
public string Path { get; set; }
+ public string GuideGroup { get; set; }
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index 51642cf5dc..2d3c203a23 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -135,7 +135,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
if (previousResult != null)
{
// Don't keep saving the same result over and over if nothing has changed
- if (previousResult.Status == result.Status && result.Status != FileSortingStatus.Success)
+ if (previousResult.Status == result.Status && previousResult.StatusMessage == result.StatusMessage && result.Status != FileSortingStatus.Success)
{
return previousResult;
}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
index 2161c14547..884e1e3225 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
@@ -125,10 +125,21 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
validIds.Add(item.Id);
+ var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview);
+ var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 30;
+
+ var defaultMetadataRefreshMode = performFullRefresh
+ ? MetadataRefreshMode.FullRefresh
+ : MetadataRefreshMode.Default;
+
+ var imageRefreshMode = performFullRefresh
+ ? ImageRefreshMode.FullRefresh
+ : ImageRefreshMode.Default;
+
var options = new MetadataRefreshOptions(_fileSystem)
{
- MetadataRefreshMode = person.Value ? MetadataRefreshMode.Default : MetadataRefreshMode.ValidationOnly,
- ImageRefreshMode = person.Value ? ImageRefreshMode.Default : ImageRefreshMode.ValidationOnly
+ MetadataRefreshMode = person.Value ? defaultMetadataRefreshMode : MetadataRefreshMode.ValidationOnly,
+ ImageRefreshMode = person.Value ? imageRefreshMode : ImageRefreshMode.ValidationOnly
};
await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index b29a7562cf..68b3f1f71e 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -13,7 +13,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
where T : class
{
private readonly object _fileDataLock = new object();
- private volatile List _items;
+ private List _items;
private readonly IJsonSerializer _jsonSerializer;
protected readonly ILogger Logger;
private readonly string _dataPath;
@@ -31,17 +31,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public IReadOnlyList GetAll()
{
- if (_items == null)
+ lock (_fileDataLock)
{
- lock (_fileDataLock)
+ if (_items == null)
{
- if (_items == null)
- {
- _items = GetItemsFromFile(_dataPath);
- }
+ _items = GetItemsFromFile(_dataPath);
}
+ return _items;
}
- return _items;
}
private List GetItemsFromFile(string path)
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index d6378d2b76..fb99e5f9db 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -466,12 +466,6 @@
PreserveNewest
-
- PreserveNewest
-
-
- PreserveNewest
-
PreserveNewest
@@ -550,9 +544,6 @@
PreserveNewest
-
- PreserveNewest
-
PreserveNewest
@@ -1402,6 +1393,42 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
PreserveNewest
@@ -2232,6 +2259,15 @@
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index a9b5020ec2..a55ae200a8 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
+# Visual Studio 14
+VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{F0E0E64C-2A6F-4E35-9533-D53AC07C2CD1}"
EndProject
@@ -521,7 +521,4 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
- GlobalSection(Performance) = preSolution
- HasPerformanceSessions = true
- EndGlobalSection
EndGlobal