aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2016-02-01 14:24:15 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2016-02-01 14:24:15 -0500
commit37352785acef4db99301c1e88624cf48133ec979 (patch)
tree15638d697cc56a0a774bf261de9814c9034f8e42
parentf14e9b8d3af98f6ffbe243b105f96f46e8cf3b06 (diff)
parentf5ebeddbf5104092ce584486689af6640125054f (diff)
Merge branch 'beta'
-rw-r--r--MediaBrowser.Api/EnvironmentService.cs8
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs2
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs6
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs3
-rw-r--r--MediaBrowser.Api/UserLibrary/PlaystateService.cs2
-rw-r--r--MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs24
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs8
-rw-r--r--MediaBrowser.Common/MediaBrowser.Common.csproj1
-rw-r--r--MediaBrowser.Common/Threading/PeriodicTimer.cs72
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs61
-rw-r--r--MediaBrowser.Controller/Entities/User.cs4
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Controller/Power/IPowerManagement.cs13
-rw-r--r--MediaBrowser.Dlna/PlayTo/Device.cs79
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToController.cs49
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToManager.cs24
-rw-r--r--MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml10
-rw-r--r--MediaBrowser.Dlna/Ssdp/SsdpHandler.cs130
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs27
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs5
-rw-r--r--MediaBrowser.Model/Configuration/UserConfiguration.cs1
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs14
-rw-r--r--MediaBrowser.Providers/People/MovieDbPersonProvider.cs18
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeriesProvider.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs61
-rw-r--r--MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs12
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs5
-rw-r--r--MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs13
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs5
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs5
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs16
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs233
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs34
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs19
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs42
-rw-r--r--MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs12
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs13
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserViewManager.cs9
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs100
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs37
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ca.json22
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/nl.json4
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj4
-rw-r--r--MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs6
-rw-r--r--MediaBrowser.Server.Implementations/packages.config2
-rw-r--r--MediaBrowser.Server.Mono/Native/BaseMonoApp.cs14
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs40
-rw-r--r--MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs6
-rw-r--r--MediaBrowser.Server.Startup.Common/INativeApp.cs7
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs2
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj1
-rw-r--r--MediaBrowser.ServerApplication/Native/WindowsApp.cs10
-rw-r--r--MediaBrowser.ServerApplication/Native/WindowsPowerManagement.cs94
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs3
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj6
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs15
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs6
61 files changed, 835 insertions, 606 deletions
diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs
index 8fdfea6b4..4e88e946f 100644
--- a/MediaBrowser.Api/EnvironmentService.cs
+++ b/MediaBrowser.Api/EnvironmentService.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
@@ -46,6 +45,11 @@ namespace MediaBrowser.Api
/// <value><c>true</c> if [include hidden]; otherwise, <c>false</c>.</value>
[ApiMember(Name = "IncludeHidden", Description = "An optional filter to include or exclude hidden files and folders. true/false", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool IncludeHidden { get; set; }
+
+ public GetDirectoryContents()
+ {
+ IncludeHidden = true;
+ }
}
[Route("/Environment/NetworkShares", "GET", Summary = "Gets shares from a network device")]
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 9e2e399d7..bb7f6bb1e 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -2192,7 +2192,7 @@ namespace MediaBrowser.Api.Playback
{
if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase))
{
- inputModifier += " -noaccurate_seek";
+ //inputModifier += " -noaccurate_seek";
}
}
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index 3b577ac01..2bf61f90b 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -141,10 +141,10 @@ namespace MediaBrowser.Api.Playback
var profile = request.DeviceProfile;
- var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
- if (caps != null)
+ if (profile == null)
{
- if (profile == null)
+ var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
+ if (caps != null)
{
profile = caps.DeviceProfile;
}
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index afe3da710..b05a1bd20 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -66,13 +66,12 @@ namespace MediaBrowser.Api
{
_config.Configuration.IsStartupWizardCompleted = true;
_config.Configuration.EnableLocalizedGuids = true;
- _config.Configuration.MergeMetadataAndImagesByName = true;
- _config.Configuration.EnableStandaloneMetadata = true;
_config.Configuration.EnableLibraryMetadataSubFolder = true;
_config.Configuration.EnableCustomPathSubFolders = true;
_config.Configuration.DisableStartupScan = true;
_config.Configuration.EnableUserViews = true;
_config.Configuration.EnableDateLastRefresh = true;
+ _config.Configuration.MergeMetadataAndImagesByName = true;
_config.SaveConfiguration();
}
diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
index 7002a3703..08c6b0ba4 100644
--- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs
+++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
@@ -370,6 +370,8 @@ namespace MediaBrowser.Api.UserLibrary
public void Post(ReportPlaybackStopped request)
{
+ Logger.Debug("ReportPlaybackStopped PlaySessionId: {0}", request.PlaySessionId ?? string.Empty);
+
if (!string.IsNullOrWhiteSpace(request.PlaySessionId))
{
ApiEntryPoint.Instance.KillTranscodingJobs(AuthorizationContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true);
diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
index bc3dc360f..ff11c889a 100644
--- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
+++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
@@ -6,7 +6,6 @@ using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
-using System.Threading;
using MoreLinq;
namespace MediaBrowser.Common.Implementations.Networking
@@ -14,22 +13,11 @@ namespace MediaBrowser.Common.Implementations.Networking
public abstract class BaseNetworkManager
{
protected ILogger Logger { get; private set; }
- private Timer _clearCacheTimer;
+ private DateTime _lastRefresh;
protected BaseNetworkManager(ILogger logger)
{
Logger = logger;
-
- // Can't use network change events due to a crash in Linux
- _clearCacheTimer = new Timer(ClearCacheTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
- }
-
- private void ClearCacheTimerCallback(object state)
- {
- lock (_localIpAddressSyncLock)
- {
- _localIpAddresses = null;
- }
}
private volatile List<IPAddress> _localIpAddresses;
@@ -41,15 +29,21 @@ namespace MediaBrowser.Common.Implementations.Networking
/// <returns>IPAddress.</returns>
public IEnumerable<IPAddress> GetLocalIpAddresses()
{
- if (_localIpAddresses == null)
+ const int cacheMinutes = 3;
+ var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes;
+
+ if (_localIpAddresses == null || forceRefresh)
{
lock (_localIpAddressSyncLock)
{
- if (_localIpAddresses == null)
+ forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes;
+
+ if (_localIpAddresses == null || forceRefresh)
{
var addresses = GetLocalIpAddressesInternal().ToList();
_localIpAddresses = addresses;
+ _lastRefresh = DateTime.UtcNow;
return addresses;
}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 95f29915d..a4ccbb6f8 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -233,7 +233,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
/// <summary>
/// The _triggers
/// </summary>
- private IEnumerable<ITaskTrigger> _triggers;
+ private volatile List<ITaskTrigger> _triggers;
/// <summary>
/// The _triggers sync lock
/// </summary>
@@ -532,7 +532,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
/// Loads the triggers.
/// </summary>
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
- private IEnumerable<ITaskTrigger> LoadTriggers()
+ private List<ITaskTrigger> LoadTriggers()
{
try
{
@@ -543,12 +543,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
catch (FileNotFoundException)
{
// File doesn't exist. No biggie. Return defaults.
- return ScheduledTask.GetDefaultTriggers();
+ return ScheduledTask.GetDefaultTriggers().ToList();
}
catch (DirectoryNotFoundException)
{
// File doesn't exist. No biggie. Return defaults.
- return ScheduledTask.GetDefaultTriggers();
+ return ScheduledTask.GetDefaultTriggers().ToList();
}
}
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index ccdb319fe..17f211d84 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -90,6 +90,7 @@
<Compile Include="Security\IRequiresRegistration.cs" />
<Compile Include="Security\ISecurityManager.cs" />
<Compile Include="Security\PaymentRequiredException.cs" />
+ <Compile Include="Threading\PeriodicTimer.cs" />
<Compile Include="Updates\IInstallationManager.cs" />
<Compile Include="Updates\InstallationEventArgs.cs" />
<Compile Include="Updates\InstallationFailedEventArgs.cs" />
diff --git a/MediaBrowser.Common/Threading/PeriodicTimer.cs b/MediaBrowser.Common/Threading/PeriodicTimer.cs
new file mode 100644
index 000000000..75ccada4e
--- /dev/null
+++ b/MediaBrowser.Common/Threading/PeriodicTimer.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Threading;
+using Microsoft.Win32;
+
+namespace MediaBrowser.Common.Threading
+{
+ public class PeriodicTimer : IDisposable
+ {
+ public Action<object> Callback { get; set; }
+ private Timer _timer;
+ private readonly object _state;
+ private readonly object _timerLock = new object();
+ private readonly TimeSpan _period;
+
+ public PeriodicTimer(Action<object> callback, object state, TimeSpan dueTime, TimeSpan period)
+ {
+ if (callback == null)
+ {
+ throw new ArgumentNullException("callback");
+ }
+
+ Callback = callback;
+ _period = period;
+ _state = state;
+
+ StartTimer(dueTime);
+ }
+
+ void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
+ {
+ if (e.Mode == PowerModes.Resume)
+ {
+ DisposeTimer();
+ StartTimer(Timeout.InfiniteTimeSpan);
+ }
+ }
+
+ private void TimerCallback(object state)
+ {
+ Callback(state);
+ }
+
+ private void StartTimer(TimeSpan dueTime)
+ {
+ lock (_timerLock)
+ {
+ _timer = new Timer(TimerCallback, _state, dueTime, _period);
+
+ SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
+ }
+ }
+
+ private void DisposeTimer()
+ {
+ SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
+
+ lock (_timerLock)
+ {
+ if (_timer != null)
+ {
+ _timer.Dispose();
+ _timer = null;
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ DisposeTimer();
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 98d1eb4ce..654c9abd3 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -1,17 +1,21 @@
-using MediaBrowser.Controller.Providers;
+using System;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
namespace MediaBrowser.Controller.Entities.Audio
{
/// <summary>
/// Class MusicAlbum
/// </summary>
- public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
+ public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
{
public MusicAlbum()
{
@@ -139,5 +143,58 @@ namespace MediaBrowser.Controller.Entities.Audio
return id;
}
+
+ public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
+ {
+ var items = GetRecursiveChildren().ToList();
+
+ var songs = items.OfType<Audio>().ToList();
+
+ var others = items.Except(songs).ToList();
+
+ var totalItems = songs.Count + others.Count;
+ var numComplete = 0;
+
+ var childUpdateType = ItemUpdateType.None;
+
+ // Refresh songs
+ foreach (var item in songs)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var updateType = await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+ childUpdateType = childUpdateType | updateType;
+
+ numComplete++;
+ double percent = numComplete;
+ percent /= totalItems;
+ progress.Report(percent * 100);
+ }
+
+ var parentRefreshOptions = refreshOptions;
+ if (childUpdateType > ItemUpdateType.None)
+ {
+ parentRefreshOptions = new MetadataRefreshOptions(refreshOptions);
+ parentRefreshOptions.MetadataRefreshMode = MetadataRefreshMode.FullRefresh;
+ }
+
+ // Refresh current item
+ await RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
+
+ // Refresh all non-songs
+ foreach (var item in others)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var updateType = await item.RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
+
+ numComplete++;
+ double percent = numComplete;
+ percent /= totalItems;
+ progress.Report(percent * 100);
+ }
+
+ progress.Report(100);
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index a9e314ede..be8521a5c 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -109,7 +109,7 @@ namespace MediaBrowser.Controller.Entities
/// <value>The last activity date.</value>
public DateTime? LastActivityDate { get; set; }
- private UserConfiguration _config;
+ private volatile UserConfiguration _config;
private readonly object _configSyncLock = new object();
[IgnoreDataMember]
public UserConfiguration Configuration
@@ -132,7 +132,7 @@ namespace MediaBrowser.Controller.Entities
set { _config = value; }
}
- private UserPolicy _policy;
+ private volatile UserPolicy _policy;
private readonly object _policySyncLock = new object();
[IgnoreDataMember]
public UserPolicy Policy
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 2227df3f0..471aa38d4 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -265,6 +265,7 @@
<Compile Include="Playlists\IPlaylistManager.cs" />
<Compile Include="Playlists\Playlist.cs" />
<Compile Include="Plugins\ILocalizablePlugin.cs" />
+ <Compile Include="Power\IPowerManagement.cs" />
<Compile Include="Providers\AlbumInfo.cs" />
<Compile Include="Providers\ArtistInfo.cs" />
<Compile Include="Providers\BookInfo.cs" />
diff --git a/MediaBrowser.Controller/Power/IPowerManagement.cs b/MediaBrowser.Controller/Power/IPowerManagement.cs
new file mode 100644
index 000000000..faa289695
--- /dev/null
+++ b/MediaBrowser.Controller/Power/IPowerManagement.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace MediaBrowser.Controller.Power
+{
+ public interface IPowerManagement
+ {
+ /// <summary>
+ /// Schedules the wake.
+ /// </summary>
+ /// <param name="utcTime">The UTC time.</param>
+ void ScheduleWake(DateTime utcTime);
+ }
+}
diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs
index 222a52736..1ec7a4ce0 100644
--- a/MediaBrowser.Dlna/PlayTo/Device.cs
+++ b/MediaBrowser.Dlna/PlayTo/Device.cs
@@ -22,14 +22,26 @@ namespace MediaBrowser.Dlna.PlayTo
#region Fields & Properties
private Timer _timer;
- private Timer _volumeTimer;
public DeviceInfo Properties { get; set; }
private int _muteVol;
public bool IsMuted { get; set; }
- public int Volume { get; set; }
+ private int _volume;
+
+ public int Volume
+ {
+ get
+ {
+ RefreshVolumeIfNeeded();
+ return _volume;
+ }
+ set
+ {
+ _volume = value;
+ }
+ }
public TimeSpan? Duration { get; set; }
@@ -93,11 +105,6 @@ namespace MediaBrowser.Dlna.PlayTo
return 1000;
}
- private int GetVolumeTimerIntervalMs()
- {
- return 5000;
- }
-
private int GetInactiveTimerIntervalMs()
{
return 20000;
@@ -107,11 +114,37 @@ namespace MediaBrowser.Dlna.PlayTo
{
_timer = new Timer(TimerCallback, null, GetPlaybackTimerIntervalMs(), GetInactiveTimerIntervalMs());
- _volumeTimer = new Timer(VolumeTimerCallback, null, Timeout.Infinite, Timeout.Infinite);
-
_timerActive = false;
}
+ private DateTime _lastVolumeRefresh;
+ private void RefreshVolumeIfNeeded()
+ {
+ if (!_timerActive)
+ {
+ return;
+ }
+
+ if (DateTime.UtcNow >= _lastVolumeRefresh.AddSeconds(5))
+ {
+ _lastVolumeRefresh = DateTime.UtcNow;
+ RefreshVolume();
+ }
+ }
+
+ private async void RefreshVolume()
+ {
+ try
+ {
+ await GetVolume().ConfigureAwait(false);
+ await GetMute().ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error updating device volume info for {0}", ex, Properties.Name);
+ }
+ }
+
private readonly object _timerLock = new object();
private bool _timerActive;
private void RestartTimer()
@@ -124,7 +157,6 @@ namespace MediaBrowser.Dlna.PlayTo
{
_logger.Debug("RestartTimer");
_timer.Change(10, GetPlaybackTimerIntervalMs());
- _volumeTimer.Change(100, GetVolumeTimerIntervalMs());
}
_timerActive = true;
@@ -150,10 +182,6 @@ namespace MediaBrowser.Dlna.PlayTo
{
_timer.Change(interval, interval);
}
- if (_volumeTimer != null)
- {
- _volumeTimer.Change(Timeout.Infinite, Timeout.Infinite);
- }
}
_timerActive = false;
@@ -440,19 +468,6 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
- private async void VolumeTimerCallback(object sender)
- {
- try
- {
- await GetVolume().ConfigureAwait(false);
- await GetMute().ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error updating device volume info for {0}", ex, Properties.Name);
- }
- }
-
private async Task GetVolume()
{
var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume");
@@ -1012,7 +1027,6 @@ namespace MediaBrowser.Dlna.PlayTo
_disposed = true;
DisposeTimer();
- DisposeVolumeTimer();
}
}
@@ -1025,15 +1039,6 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
- private void DisposeVolumeTimer()
- {
- if (_volumeTimer != null)
- {
- _volumeTimer.Dispose();
- _volumeTimer = null;
- }
- }
-
#endregion
public override string ToString()
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
index cb3629678..7e021b877 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
@@ -37,11 +37,28 @@ namespace MediaBrowser.Dlna.PlayTo
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly string _serverAddress;
private readonly string _accessToken;
+ private readonly DateTime _creationTime;
public bool IsSessionActive
{
get
{
+ var lastDateKnownActivity = new[] { _creationTime, _device.DateLastActivity }.Max();
+
+ if (DateTime.UtcNow >= lastDateKnownActivity.AddSeconds(120))
+ {
+ try
+ {
+ // Session is inactive, mark it for Disposal and don't start the elapsed timer.
+ _sessionManager.ReportSessionEnded(_session.Id);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error in ReportSessionEnded", ex);
+ }
+ return false;
+ }
+
return _device != null;
}
}
@@ -55,8 +72,6 @@ namespace MediaBrowser.Dlna.PlayTo
get { return IsSessionActive; }
}
- private Timer _updateTimer;
-
public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
{
_session = session;
@@ -72,6 +87,7 @@ namespace MediaBrowser.Dlna.PlayTo
_mediaSourceManager = mediaSourceManager;
_accessToken = accessToken;
_logger = logger;
+ _creationTime = DateTime.UtcNow;
}
public void Init(Device device)
@@ -84,8 +100,6 @@ namespace MediaBrowser.Dlna.PlayTo
_device.Start();
_deviceDiscovery.DeviceLeft += _deviceDiscovery_DeviceLeft;
-
- _updateTimer = new Timer(updateTimer_Elapsed, null, 60000, 60000);
}
void _deviceDiscovery_DeviceLeft(object sender, SsdpMessageEventArgs e)
@@ -117,22 +131,6 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
- private void updateTimer_Elapsed(object state)
- {
- if (DateTime.UtcNow >= _device.DateLastActivity.AddSeconds(120))
- {
- try
- {
- // Session is inactive, mark it for Disposal and don't start the elapsed timer.
- _sessionManager.ReportSessionEnded(_session.Id);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in ReportSessionEnded", ex);
- }
- }
- }
-
async void _device_MediaChanged(object sender, MediaChangedEventArgs e)
{
try
@@ -634,21 +632,10 @@ namespace MediaBrowser.Dlna.PlayTo
_device.MediaChanged -= _device_MediaChanged;
_deviceDiscovery.DeviceLeft -= _deviceDiscovery_DeviceLeft;
- DisposeUpdateTimer();
-
_device.Dispose();
}
}
- private void DisposeUpdateTimer()
- {
- if (_updateTimer != null)
- {
- _updateTimer.Dispose();
- _updateTimer = null;
- }
- }
-
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index 6c79007c4..94f8104be 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -36,7 +36,7 @@ namespace MediaBrowser.Dlna.PlayTo
private readonly IMediaSourceManager _mediaSourceManager;
private readonly List<string> _nonRendererUrls = new List<string>();
- private Timer _clearNonRenderersTimer;
+ private DateTime _lastRendererClear;
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
{
@@ -57,19 +57,9 @@ namespace MediaBrowser.Dlna.PlayTo
public void Start()
{
- _clearNonRenderersTimer = new Timer(OnClearUrlTimerCallback, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
-
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
}
- private void OnClearUrlTimerCallback(object state)
- {
- lock (_nonRendererUrls)
- {
- _nonRendererUrls.Clear();
- }
- }
-
async void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
{
string usn;
@@ -99,6 +89,12 @@ namespace MediaBrowser.Dlna.PlayTo
lock (_nonRendererUrls)
{
+ if ((DateTime.UtcNow - _lastRendererClear).TotalMinutes >= 10)
+ {
+ _nonRendererUrls.Clear();
+ _lastRendererClear = DateTime.UtcNow;
+ }
+
if (_nonRendererUrls.Contains(location, StringComparer.OrdinalIgnoreCase))
{
return;
@@ -181,12 +177,6 @@ namespace MediaBrowser.Dlna.PlayTo
public void Dispose()
{
_deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
-
- if (_clearNonRenderersTimer != null)
- {
- _clearNonRenderersTimer.Dispose();
- _clearNonRenderersTimer = null;
- }
}
}
}
diff --git a/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
index 5bfd37726..98e780a25 100644
--- a/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
@@ -58,7 +58,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "avi",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
- AudioCodec = "ac3,dca,mp2,mp3,pcm"
+ AudioCodec = "ac3,dca,mp2,mp3,pcm,dca"
},
new DirectPlayProfile
@@ -66,7 +66,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "mpeg",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video",
- AudioCodec = "ac3,dca,mp2,mp3,pcm"
+ AudioCodec = "ac3,dca,mp2,mp3,pcm,dca"
},
new DirectPlayProfile
@@ -74,7 +74,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "mkv",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
- AudioCodec = "ac3,dca,aac,mp2,mp3,pcm"
+ AudioCodec = "ac3,dca,aac,mp2,mp3,pcm,dca"
},
new DirectPlayProfile
@@ -82,7 +82,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "ts",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,h264,vc1",
- AudioCodec = "ac3,dca,mp2,mp3,aac"
+ AudioCodec = "ac3,dca,mp2,mp3,aac,dca"
},
new DirectPlayProfile
@@ -90,7 +90,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "mp4,mov",
Type = DlnaProfileType.Video,
VideoCodec = "h264,mpeg4",
- AudioCodec = "ac3,aac,mp2,mp3"
+ AudioCodec = "ac3,aac,mp2,mp3,dca"
},
new DirectPlayProfile
diff --git a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
index 10b642bba..e17fc087b 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
@@ -37,11 +37,11 @@
<IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes />
<DirectPlayProfiles>
- <DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
- <DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
- <DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
- <DirectPlayProfile container="ts" audioCodec="ac3,dca,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
- <DirectPlayProfile container="mp4,mov" audioCodec="ac3,aac,mp2,mp3" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
+ <DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video" type="Video" />
+ <DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="ac3,dca,mp2,mp3,aac,dca" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
+ <DirectPlayProfile container="mp4,mov" audioCodec="ac3,aac,mp2,mp3,dca" videoCodec="h264,mpeg4" type="Video" />
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="vc1" type="Video" />
<DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" />
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
index 32c369a8f..f800a12c1 100644
--- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
+++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
@@ -33,12 +33,8 @@ namespace MediaBrowser.Dlna.Ssdp
private readonly IPAddress _ssdpIp = IPAddress.Parse(SSDPAddr);
private readonly IPEndPoint _ssdpEndp = new IPEndPoint(IPAddress.Parse(SSDPAddr), SSDPPort);
- private Timer _queueTimer;
private Timer _notificationTimer;
- private readonly AutoResetEvent _datagramPosted = new AutoResetEvent(false);
- private readonly ConcurrentQueue<Datagram> _messageQueue = new ConcurrentQueue<Datagram>();
-
private bool _isDisposed;
private readonly ConcurrentDictionary<Guid, List<UpnpDevice>> _devices = new ConcurrentDictionary<Guid, List<UpnpDevice>>();
@@ -121,9 +117,13 @@ namespace MediaBrowser.Dlna.Ssdp
public void Start()
{
- RestartSocketListener();
+ DisposeSocket();
+ StopAliveNotifier();
+ RestartSocketListener();
ReloadAliveNotifier();
+
+ SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
}
@@ -131,7 +131,7 @@ namespace MediaBrowser.Dlna.Ssdp
{
if (e.Mode == PowerModes.Resume)
{
- NotifyAll();
+ Start();
}
}
@@ -154,7 +154,7 @@ namespace MediaBrowser.Dlna.Ssdp
SendDatagram("M-SEARCH * HTTP/1.1", values, _ssdpEndp, localIp, true, 2);
}
- public void SendDatagram(string header,
+ public async void SendDatagram(string header,
Dictionary<string, string> values,
EndPoint endpoint,
EndPoint localAddress,
@@ -162,28 +162,18 @@ namespace MediaBrowser.Dlna.Ssdp
int sendCount)
{
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
- var queued = false;
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
for (var i = 0; i < sendCount; i++)
{
- var dgram = new Datagram(endpoint, localAddress, _logger, msg, isBroadcast, enableDebugLogging);
-
- if (_messageQueue.Count == 0)
+ if (i > 0)
{
- dgram.Send();
+ await Task.Delay(500).ConfigureAwait(false);
}
- else
- {
- _messageQueue.Enqueue(dgram);
- queued = true;
- }
- }
- if (queued)
- {
- StartQueueTimer();
+ var dgram = new Datagram(endpoint, localAddress, _logger, msg, isBroadcast, enableDebugLogging);
+ dgram.Send();
}
}
@@ -254,47 +244,10 @@ namespace MediaBrowser.Dlna.Ssdp
}
}
- private readonly object _queueTimerSyncLock = new object();
- private void StartQueueTimer()
- {
- lock (_queueTimerSyncLock)
- {
- if (_queueTimer == null)
- {
- _queueTimer = new Timer(QueueTimerCallback, null, 500, Timeout.Infinite);
- }
- else
- {
- _queueTimer.Change(500, Timeout.Infinite);
- }
- }
- }
-
- private void QueueTimerCallback(object state)
- {
- Datagram msg;
- while (_messageQueue.TryDequeue(out msg))
- {
- msg.Send();
- }
-
- _datagramPosted.Set();
-
- if (_messageQueue.Count > 0)
- {
- StartQueueTimer();
- }
- else
- {
- DisposeQueueTimer();
- }
- }
-
private void RestartSocketListener()
{
if (_isDisposed)
{
- StopSocketRetryTimer();
return;
}
@@ -304,8 +257,6 @@ namespace MediaBrowser.Dlna.Ssdp
_logger.Info("MultiCast socket created");
- StopSocketRetryTimer();
-
Receive();
}
catch (Exception ex)
@@ -315,31 +266,6 @@ namespace MediaBrowser.Dlna.Ssdp
}
}
- private Timer _socketRetryTimer;
- private readonly object _socketRetryLock = new object();
- private void StartSocketRetryTimer()
- {
- lock (_socketRetryLock)
- {
- if (_socketRetryTimer == null)
- {
- _socketRetryTimer = new Timer(s => RestartSocketListener(), null, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
- }
- }
- }
-
- private void StopSocketRetryTimer()
- {
- lock (_socketRetryLock)
- {
- if (_socketRetryTimer != null)
- {
- _socketRetryTimer.Dispose();
- _socketRetryTimer = null;
- }
- }
- }
-
private void Receive()
{
try
@@ -448,16 +374,9 @@ namespace MediaBrowser.Dlna.Ssdp
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
_isDisposed = true;
- while (_messageQueue.Count != 0)
- {
- _datagramPosted.WaitOne();
- }
DisposeSocket();
- DisposeQueueTimer();
- DisposeNotificationTimer();
-
- _datagramPosted.Dispose();
+ StopAliveNotifier();
}
private void DisposeSocket()
@@ -470,18 +389,6 @@ namespace MediaBrowser.Dlna.Ssdp
}
}
- private void DisposeQueueTimer()
- {
- lock (_queueTimerSyncLock)
- {
- if (_queueTimer != null)
- {
- _queueTimer.Dispose();
- _queueTimer = null;
- }
- }
- }
-
private Socket CreateMulticastSocket()
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
@@ -534,14 +441,7 @@ namespace MediaBrowser.Dlna.Ssdp
public void RegisterNotification(Guid uuid, Uri descriptionUri, IPAddress address, IEnumerable<string> services)
{
- List<UpnpDevice> list;
- lock (_devices)
- {
- if (!_devices.TryGetValue(uuid, out list))
- {
- _devices.TryAdd(uuid, list = new List<UpnpDevice>());
- }
- }
+ var list = _devices.GetOrAdd(uuid, new List<UpnpDevice>());
list.AddRange(services.Select(i => new UpnpDevice(uuid, i, descriptionUri, address)));
@@ -572,7 +472,7 @@ namespace MediaBrowser.Dlna.Ssdp
if (!config.BlastAliveMessages)
{
- DisposeNotificationTimer();
+ StopAliveNotifier();
return;
}
@@ -599,7 +499,7 @@ namespace MediaBrowser.Dlna.Ssdp
}
}
- private void DisposeNotificationTimer()
+ private void StopAliveNotifier()
{
lock (_notificationTimerSyncLock)
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index ba0790bf3..2a3a416ad 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -292,16 +292,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
return false;
}
- // If the video codec is not some form of mpeg, then take a shortcut and limit this to containers that are likely to have interlaced content
- if ((videoStream.Codec ?? string.Empty).IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) == -1)
+ var formats = (video.Container ?? string.Empty).Split(',').ToList();
+ var enableInterlacedDection = formats.Contains("vob", StringComparer.OrdinalIgnoreCase) &&
+ formats.Contains("m2ts", StringComparer.OrdinalIgnoreCase) &&
+ formats.Contains("ts", StringComparer.OrdinalIgnoreCase) &&
+ formats.Contains("mpegts", StringComparer.OrdinalIgnoreCase) &&
+ formats.Contains("wtv", StringComparer.OrdinalIgnoreCase);
+
+ // If it's mpeg based, assume true
+ if ((videoStream.Codec ?? string.Empty).IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) != -1)
{
- var formats = (video.Container ?? string.Empty).Split(',').ToList();
-
- if (!formats.Contains("vob", StringComparer.OrdinalIgnoreCase) &&
- !formats.Contains("m2ts", StringComparer.OrdinalIgnoreCase) &&
- !formats.Contains("ts", StringComparer.OrdinalIgnoreCase) &&
- !formats.Contains("mpegts", StringComparer.OrdinalIgnoreCase) &&
- !formats.Contains("wtv", StringComparer.OrdinalIgnoreCase))
+ if (enableInterlacedDection)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ // If the video codec is not some form of mpeg, then take a shortcut and limit this to containers that are likely to have interlaced content
+ if (!enableInterlacedDection)
{
return false;
}
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index fb22637f9..152bdd993 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -164,7 +164,7 @@ namespace MediaBrowser.Model.Configuration
/// different directories and files.
/// </summary>
/// <value>The file watcher delay.</value>
- public int RealtimeLibraryMonitorDelay { get; set; }
+ public int LibraryMonitorDelay { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [enable dashboard response caching].
@@ -181,7 +181,6 @@ namespace MediaBrowser.Model.Configuration
public string DashboardSourcePath { get; set; }
public bool MergeMetadataAndImagesByName { get; set; }
- public bool EnableStandaloneMetadata { get; set; }
/// <summary>
/// Gets or sets the image saving convention.
@@ -256,7 +255,7 @@ namespace MediaBrowser.Model.Configuration
MinResumeDurationSeconds = 300;
EnableLibraryMonitor = AutoOnOff.Auto;
- RealtimeLibraryMonitorDelay = 40;
+ LibraryMonitorDelay = 60;
EnableInternetProviders = true;
FindInternetTrailers = true;
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index ab3a861a3..819948909 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -48,6 +48,7 @@ namespace MediaBrowser.Model.Configuration
public string[] PlainFolderViews { get; set; }
public bool HidePlayedInLatest { get; set; }
+ public bool DisplayChannelsInline { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="UserConfiguration" /> class.
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index efa6ff0cf..8094aa58d 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -213,7 +213,7 @@ namespace MediaBrowser.Providers.MediaInfo
}
var chapters = mediaInfo.Chapters ?? new List<ChapterInfo>();
- if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay))
+ if (blurayInfo != null)
{
FetchBdInfo(video, chapters, mediaStreams, blurayInfo);
}
@@ -360,7 +360,15 @@ namespace MediaBrowser.Providers.MediaInfo
/// <returns>VideoStream.</returns>
private BlurayDiscInfo GetBDInfo(string path)
{
- return _blurayExaminer.GetDiscInfo(path);
+ try
+ {
+ return _blurayExaminer.GetDiscInfo(path);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting BDInfo", ex);
+ return null;
+ }
}
private void FetchEmbeddedInfo(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions options)
@@ -628,7 +636,7 @@ namespace MediaBrowser.Providers.MediaInfo
FetchFromDvdLib(item, mount);
}
- if (item.VideoType == VideoType.BluRay || (item.IsoType.HasValue && item.IsoType.Value == IsoType.BluRay))
+ if (blurayDiscInfo != null)
{
item.PlayableStreamFileNames = blurayDiscInfo.Files.ToList();
}
diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
index 5c5919709..14304c2eb 100644
--- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
+++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
@@ -38,7 +38,7 @@ namespace MediaBrowser.Providers.People
private int _requestCount;
private readonly object _requestCountLock = new object();
- private Timer _requestCountReset;
+ private DateTime _lastRequestCountReset;
public MovieDbPersonProvider(IFileSystem fileSystem, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogger logger)
{
@@ -48,16 +48,6 @@ namespace MediaBrowser.Providers.People
_httpClient = httpClient;
_logger = logger;
Current = this;
-
- _requestCountReset = new Timer(OnRequestThrottleTimerFired, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1));
- }
-
- private void OnRequestThrottleTimerFired(object state)
- {
- lock (_requestCountLock)
- {
- _requestCount = 0;
- }
}
public string Name
@@ -101,6 +91,12 @@ namespace MediaBrowser.Providers.People
{
lock (_requestCountLock)
{
+ if ((DateTime.UtcNow - _lastRequestCountReset).TotalHours >= 1)
+ {
+ _requestCount = 0;
+ _lastRequestCountReset = DateTime.UtcNow;
+ }
+
var requestCount = _requestCount;
if (requestCount >= 5)
diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
index 313ca9074..4a7ae57fb 100644
--- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
@@ -238,7 +238,7 @@ namespace MediaBrowser.Providers.TV
throw new ArgumentNullException("seriesId");
}
- var url = string.Format(SeriesGetZip, TVUtils.TvdbApiKey, seriesId, preferredMetadataLanguage);
+ var url = string.Format(SeriesGetZip, TVUtils.TvdbApiKey, seriesId, NormalizeLanguage(preferredMetadataLanguage));
using (var zipStream = await _httpClient.Get(new HttpRequestOptions
{
@@ -268,7 +268,7 @@ namespace MediaBrowser.Providers.TV
await SanitizeXmlFile(file).ConfigureAwait(false);
}
- var downloadLangaugeXmlFile = Path.Combine(seriesDataPath, preferredMetadataLanguage + ".xml");
+ var downloadLangaugeXmlFile = Path.Combine(seriesDataPath, NormalizeLanguage(preferredMetadataLanguage) + ".xml");
var saveAsLanguageXmlFile = Path.Combine(seriesDataPath, saveAsMetadataLanguage + ".xml");
if (!string.Equals(downloadLangaugeXmlFile, saveAsLanguageXmlFile, StringComparison.OrdinalIgnoreCase))
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index b115c3bfd..284556c72 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -29,7 +29,7 @@ using CommonIO;
namespace MediaBrowser.Server.Implementations.Channels
{
- public class ChannelManager : IChannelManager, IDisposable
+ public class ChannelManager : IChannelManager
{
private IChannel[] _channels;
@@ -47,11 +47,6 @@ namespace MediaBrowser.Server.Implementations.Channels
private readonly ILocalizationManager _localization;
private readonly ConcurrentDictionary<Guid, bool> _refreshedItems = new ConcurrentDictionary<Guid, bool>();
- private readonly ConcurrentDictionary<string, int> _downloadCounts = new ConcurrentDictionary<string, int>();
-
- private Timer _refreshTimer;
- private Timer _clearDownloadCountsTimer;
-
public ChannelManager(IUserManager userManager, IDtoService dtoService, ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem, IUserDataManager userDataManager, IJsonSerializer jsonSerializer, ILocalizationManager localization, IHttpClient httpClient, IProviderManager providerManager)
{
_userManager = userManager;
@@ -65,9 +60,6 @@ namespace MediaBrowser.Server.Implementations.Channels
_localization = localization;
_httpClient = httpClient;
_providerManager = providerManager;
-
- _refreshTimer = new Timer(s => _refreshedItems.Clear(), null, TimeSpan.FromHours(3), TimeSpan.FromHours(3));
- _clearDownloadCountsTimer = new Timer(s => _downloadCounts.Clear(), null, TimeSpan.FromHours(24), TimeSpan.FromHours(24));
}
private TimeSpan CacheLength
@@ -206,6 +198,8 @@ namespace MediaBrowser.Server.Implementations.Channels
public async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken)
{
+ _refreshedItems.Clear();
+
var allChannelsList = GetAllChannels().ToList();
var numComplete = 0;
@@ -1471,12 +1465,6 @@ namespace MediaBrowser.Server.Implementations.Channels
var limit = features.DailyDownloadLimit;
- if (!ValidateDownloadLimit(host, limit))
- {
- _logger.Error(string.Format("Download limit has been reached for {0}", channel.Name));
- throw new ChannelDownloadException(string.Format("Download limit has been reached for {0}", channel.Name));
- }
-
foreach (var header in source.RequiredHttpHeaders)
{
options.RequestHeaders[header.Key] = header.Value;
@@ -1495,8 +1483,6 @@ namespace MediaBrowser.Server.Implementations.Channels
};
}
- IncrementDownloadCount(host, limit);
-
if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase) && response.ContentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
{
var extension = response.ContentType.Split('/')
@@ -1531,46 +1517,5 @@ namespace MediaBrowser.Server.Implementations.Channels
}
}
-
- private void IncrementDownloadCount(string key, int? limit)
- {
- if (!limit.HasValue)
- {
- return;
- }
-
- int current;
- _downloadCounts.TryGetValue(key, out current);
-
- current++;
- _downloadCounts.AddOrUpdate(key, current, (k, v) => current);
- }
-
- private bool ValidateDownloadLimit(string key, int? limit)
- {
- if (!limit.HasValue)
- {
- return true;
- }
-
- int current;
- _downloadCounts.TryGetValue(key, out current);
-
- return current < limit.Value;
- }
-
- public void Dispose()
- {
- if (_clearDownloadCountsTimer != null)
- {
- _clearDownloadCountsTimer.Dispose();
- _clearDownloadCountsTimer = null;
- }
- if (_refreshTimer != null)
- {
- _refreshTimer.Dispose();
- _refreshTimer = null;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
index a7d3854e7..d7df37332 100644
--- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -121,20 +121,12 @@ namespace MediaBrowser.Server.Implementations.Configuration
((ServerApplicationPaths)ApplicationPaths).InternalMetadataPath = metadataPath;
- if (Configuration.MergeMetadataAndImagesByName)
- {
- ((ServerApplicationPaths)ApplicationPaths).ItemsByNamePath = ((ServerApplicationPaths)ApplicationPaths).InternalMetadataPath;
- }
+ ((ServerApplicationPaths)ApplicationPaths).ItemsByNamePath = ((ServerApplicationPaths)ApplicationPaths).InternalMetadataPath;
}
private string GetInternalMetadataPath()
{
- if (Configuration.EnableStandaloneMetadata)
- {
- return Path.Combine(ApplicationPaths.ProgramDataPath, "metadata");
- }
-
- return null;
+ return Path.Combine(ApplicationPaths.ProgramDataPath, "metadata");
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
index 6dab136a5..12de5f6ef 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
@@ -13,12 +13,13 @@ using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Threading;
namespace MediaBrowser.Server.Implementations.Connect
{
public class ConnectEntryPoint : IServerEntryPoint
{
- private Timer _timer;
+ private PeriodicTimer _timer;
private readonly IHttpClient _httpClient;
private readonly IApplicationPaths _appPaths;
private readonly ILogger _logger;
@@ -43,7 +44,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
Task.Run(() => LoadCachedAddress());
- _timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(3));
+ _timer = new PeriodicTimer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(3));
}
private readonly string[] _ipLookups = { "http://bot.whatismyipaddress.com", "https://connect.emby.media/service/ip" };
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs b/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
index 43b1e693c..9e4a45253 100644
--- a/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
@@ -25,7 +25,7 @@ namespace MediaBrowser.Server.Implementations.Devices
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
- private ConcurrentBag<DeviceInfo> _devices;
+ private List<DeviceInfo> _devices;
public DeviceRepository(IApplicationPaths appPaths, IJsonSerializer json, ILogger logger, IFileSystem fileSystem)
{
@@ -93,17 +93,14 @@ namespace MediaBrowser.Server.Implementations.Devices
public IEnumerable<DeviceInfo> GetDevices()
{
- if (_devices == null)
+ lock (_syncLock)
{
- lock (_syncLock)
+ if (_devices == null)
{
- if (_devices == null)
- {
- _devices = new ConcurrentBag<DeviceInfo>(LoadDevices());
- }
+ _devices = LoadDevices().ToList();
}
+ return _devices.ToList();
}
- return _devices.ToList();
}
private IEnumerable<DeviceInfo> LoadDevices()
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
index a2ffa9aff..2b2c338dd 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
@@ -11,6 +11,7 @@ using System.IO;
using System.Net;
using System.Text;
using System.Threading;
+using MediaBrowser.Common.Threading;
namespace MediaBrowser.Server.Implementations.EntryPoints
{
@@ -21,7 +22,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
private readonly IServerConfigurationManager _config;
private readonly ISsdpHandler _ssdp;
- private Timer _timer;
+ private PeriodicTimer _timer;
private bool _isStarted;
public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config, ISsdpHandler ssdp)
@@ -95,7 +96,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
NatUtility.UnhandledException += NatUtility_UnhandledException;
NatUtility.StartDiscovery();
- _timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
+ _timer = new PeriodicTimer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
_ssdp.MessageReceived += _ssdp_MessageReceived;
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs b/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs
index 701cf21fb..efda36821 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Model.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Threading;
namespace MediaBrowser.Server.Implementations.EntryPoints
{
@@ -22,7 +23,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
/// </summary>
private readonly ILogger _logger;
- private Timer _timer;
+ private PeriodicTimer _timer;
/// <summary>
/// Initializes a new instance of the <see cref="LoadRegistrations" /> class.
@@ -41,7 +42,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
/// </summary>
public void Run()
{
- _timer = new Timer(s => LoadAllRegistrations(), null, TimeSpan.FromMilliseconds(100), TimeSpan.FromHours(12));
+ _timer = new PeriodicTimer(s => LoadAllRegistrations(), null, TimeSpan.FromMilliseconds(100), TimeSpan.FromHours(12));
}
private async Task LoadAllRegistrations()
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs
index c3b9c0d4d..d8aef909b 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs
@@ -9,6 +9,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.EntryPoints
{
@@ -23,7 +24,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
private readonly ISessionManager _sessionManager;
private readonly IUserManager _userManager;
- private Timer _timer;
private readonly TimeSpan _frequency = TimeSpan.FromHours(24);
private readonly ConcurrentDictionary<Guid, ClientInfo> _apps = new ConcurrentDictionary<Guid, ClientInfo>();
@@ -95,16 +95,16 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
return info;
}
- public void Run()
+ public async void Run()
{
- _timer = new Timer(OnTimerFired, null, TimeSpan.FromMilliseconds(5000), _frequency);
+ await Task.Delay(5000).ConfigureAwait(false);
+ OnTimerFired();
}
/// <summary>
/// Called when [timer fired].
/// </summary>
- /// <param name="state">The state.</param>
- private async void OnTimerFired(object state)
+ private async void OnTimerFired()
{
try
{
@@ -121,12 +121,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
public void Dispose()
{
_sessionManager.SessionStarted -= _sessionManager_SessionStarted;
-
- if (_timer != null)
- {
- _timer.Dispose();
- _timer = null;
- }
}
}
}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index 26392f5a9..73cc5ab01 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -76,50 +76,50 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
var seasonNumber = episodeInfo.SeasonNumber;
- result.ExtractedSeasonNumber = seasonNumber;
-
- // Passing in true will include a few extra regex's
- var episodeNumber = episodeInfo.EpisodeNumber;
-
- result.ExtractedEpisodeNumber = episodeNumber;
-
- var premiereDate = episodeInfo.IsByDate ?
- new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value) :
- (DateTime?)null;
-
- if (episodeInfo.IsByDate || (seasonNumber.HasValue && episodeNumber.HasValue))
- {
- if (episodeInfo.IsByDate)
- {
- _logger.Debug("Extracted information from {0}. Series name {1}, Date {2}", path, seriesName, premiereDate.Value);
- }
- else
- {
- _logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, seasonNumber, episodeNumber);
- }
-
- var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber;
-
- result.ExtractedEndingEpisodeNumber = endingEpisodeNumber;
-
- await OrganizeEpisode(path,
- seriesName,
- seasonNumber,
- episodeNumber,
- endingEpisodeNumber,
- premiereDate,
- options,
- overwriteExisting,
- result,
- cancellationToken).ConfigureAwait(false);
- }
- else
- {
- var msg = string.Format("Unable to determine episode number from {0}", path);
- result.Status = FileSortingStatus.Failure;
- result.StatusMessage = msg;
- _logger.Warn(msg);
- }
+ result.ExtractedSeasonNumber = seasonNumber;
+
+ // Passing in true will include a few extra regex's
+ var episodeNumber = episodeInfo.EpisodeNumber;
+
+ result.ExtractedEpisodeNumber = episodeNumber;
+
+ var premiereDate = episodeInfo.IsByDate ?
+ new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value) :
+ (DateTime?)null;
+
+ if (episodeInfo.IsByDate || (seasonNumber.HasValue && episodeNumber.HasValue))
+ {
+ if (episodeInfo.IsByDate)
+ {
+ _logger.Debug("Extracted information from {0}. Series name {1}, Date {2}", path, seriesName, premiereDate.Value);
+ }
+ else
+ {
+ _logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, seasonNumber, episodeNumber);
+ }
+
+ var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber;
+
+ result.ExtractedEndingEpisodeNumber = endingEpisodeNumber;
+
+ await OrganizeEpisode(path,
+ seriesName,
+ seasonNumber,
+ episodeNumber,
+ endingEpisodeNumber,
+ premiereDate,
+ options,
+ overwriteExisting,
+ result,
+ cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ var msg = string.Format("Unable to determine episode number from {0}", path);
+ result.Status = FileSortingStatus.Failure;
+ result.StatusMessage = msg;
+ _logger.Warn(msg);
+ }
}
else
{
@@ -151,32 +151,32 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
var series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId));
- await OrganizeEpisode(result.OriginalPath,
- series,
- request.SeasonNumber,
- request.EpisodeNumber,
- request.EndingEpisodeNumber,
- null,
- options,
- true,
- result,
- cancellationToken).ConfigureAwait(false);
+ await OrganizeEpisode(result.OriginalPath,
+ series,
+ request.SeasonNumber,
+ request.EpisodeNumber,
+ request.EndingEpisodeNumber,
+ null,
+ options,
+ true,
+ result,
+ cancellationToken).ConfigureAwait(false);
await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);
return result;
}
- private Task OrganizeEpisode(string sourcePath,
- string seriesName,
- int? seasonNumber,
- int? episodeNumber,
- int? endingEpiosdeNumber,
- DateTime? premiereDate,
- TvFileOrganizationOptions options,
- bool overwriteExisting,
- FileOrganizationResult result,
- CancellationToken cancellationToken)
+ private Task OrganizeEpisode(string sourcePath,
+ string seriesName,
+ int? seasonNumber,
+ int? episodeNumber,
+ int? endingEpiosdeNumber,
+ DateTime? premiereDate,
+ TvFileOrganizationOptions options,
+ bool overwriteExisting,
+ FileOrganizationResult result,
+ CancellationToken cancellationToken)
{
var series = GetMatchingSeries(seriesName, result);
@@ -189,33 +189,33 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
return Task.FromResult(true);
}
- return OrganizeEpisode(sourcePath,
- series,
- seasonNumber,
- episodeNumber,
- endingEpiosdeNumber,
- premiereDate,
- options,
- overwriteExisting,
- result,
- cancellationToken);
+ return OrganizeEpisode(sourcePath,
+ series,
+ seasonNumber,
+ episodeNumber,
+ endingEpiosdeNumber,
+ premiereDate,
+ options,
+ overwriteExisting,
+ result,
+ cancellationToken);
}
- private async Task OrganizeEpisode(string sourcePath,
- Series series,
- int? seasonNumber,
- int? episodeNumber,
- int? endingEpiosdeNumber,
- DateTime? premiereDate,
- TvFileOrganizationOptions options,
- bool overwriteExisting,
- FileOrganizationResult result,
- CancellationToken cancellationToken)
+ private async Task OrganizeEpisode(string sourcePath,
+ Series series,
+ int? seasonNumber,
+ int? episodeNumber,
+ int? endingEpiosdeNumber,
+ DateTime? premiereDate,
+ TvFileOrganizationOptions options,
+ bool overwriteExisting,
+ FileOrganizationResult result,
+ CancellationToken cancellationToken)
{
_logger.Info("Sorting file {0} into series {1}", sourcePath, series.Path);
// Proceed to sort the file
- var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options, cancellationToken).ConfigureAwait(false);
+ var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options, cancellationToken).ConfigureAwait(false);
if (string.IsNullOrEmpty(newPath))
{
@@ -324,17 +324,17 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
}
}
- private List<string> GetOtherDuplicatePaths(string targetPath,
- Series series,
- int? seasonNumber,
- int? episodeNumber,
- int? endingEpisodeNumber)
+ private List<string> GetOtherDuplicatePaths(string targetPath,
+ Series series,
+ int? seasonNumber,
+ int? episodeNumber,
+ int? endingEpisodeNumber)
{
- // TODO: Support date-naming?
- if (!seasonNumber.HasValue || episodeNumber.HasValue)
- {
- return new List<string> ();
- }
+ // TODO: Support date-naming?
+ if (!seasonNumber.HasValue || episodeNumber.HasValue)
+ {
+ return new List<string>();
+ }
var episodePaths = series.GetRecursiveChildren()
.OfType<Episode>()
@@ -462,16 +462,18 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
/// <param name="seasonNumber">The season number.</param>
/// <param name="episodeNumber">The episode number.</param>
/// <param name="endingEpisodeNumber">The ending episode number.</param>
+ /// <param name="premiereDate">The premiere date.</param>
/// <param name="options">The options.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>System.String.</returns>
- private async Task<string> GetNewPath(string sourcePath,
- Series series,
- int? seasonNumber,
- int? episodeNumber,
- int? endingEpisodeNumber,
- DateTime? premiereDate,
- TvFileOrganizationOptions options,
- CancellationToken cancellationToken)
+ private async Task<string> GetNewPath(string sourcePath,
+ Series series,
+ int? seasonNumber,
+ int? episodeNumber,
+ int? endingEpisodeNumber,
+ DateTime? premiereDate,
+ TvFileOrganizationOptions options,
+ CancellationToken cancellationToken)
{
var episodeInfo = new EpisodeInfo
{
@@ -481,7 +483,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
MetadataLanguage = series.GetPreferredMetadataLanguage(),
ParentIndexNumber = seasonNumber,
SeriesProviderIds = series.ProviderIds,
- PremiereDate = premiereDate
+ PremiereDate = premiereDate
};
var searchResults = await _providerManager.GetRemoteSearchResults<Episode, EpisodeInfo>(new RemoteSearchQuery<EpisodeInfo>
@@ -491,22 +493,25 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
}, cancellationToken).ConfigureAwait(false);
var episode = searchResults.FirstOrDefault();
-
- string episodeName = string.Empty;
if (episode == null)
{
var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
_logger.Warn(msg);
- //throw new Exception(msg);
+ return null;
}
- else
- {
- episodeName = episode.Name;
- }
- seasonNumber = seasonNumber ?? episode.ParentIndexNumber;
- episodeNumber = episodeNumber ?? episode.IndexNumber;
+ var episodeName = episode.Name;
+
+ //if (string.IsNullOrWhiteSpace(episodeName))
+ //{
+ // var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
+ // _logger.Warn(msg);
+ // return null;
+ //}
+
+ seasonNumber = seasonNumber ?? episode.ParentIndexNumber;
+ episodeNumber = episodeNumber ?? episode.IndexNumber;
var newPath = GetSeasonFolderPath(series, seasonNumber.Value, options);
@@ -579,7 +584,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
seriesName = _fileSystem.GetValidFilename(seriesName).Trim();
- if (string.IsNullOrEmpty(episodeTitle))
+ if (string.IsNullOrWhiteSpace(episodeTitle))
{
episodeTitle = string.Empty;
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 6a23a8497..038116703 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -256,6 +256,25 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
}
+ private readonly Dictionary<string, int> _skipLogExtensions = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
+ {
+ {".js", 0},
+ {".css", 0},
+ {".woff", 0},
+ {".woff2", 0},
+ {".ttf", 0},
+ {".html", 0}
+ };
+
+ private bool EnableLogging(string url)
+ {
+ var parts = url.Split(new[] { '?' }, 2);
+
+ var extension = Path.GetExtension(parts[0]);
+
+ return string.IsNullOrWhiteSpace(extension) || !_skipLogExtensions.ContainsKey(extension);
+ }
+
/// <summary>
/// Overridable method that can be used to implement a custom hnandler
/// </summary>
@@ -271,6 +290,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer
var operationName = httpReq.OperationName;
var localPath = url.LocalPath;
+ var urlString = url.OriginalString;
+ var enableLog = EnableLogging(urlString);
+
+ if (enableLog)
+ {
+ LoggerUtils.LogRequest(_logger, urlString, httpReq.HttpMethod, httpReq.UserAgent);
+ }
+
if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase))
{
@@ -333,15 +360,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer
task.ContinueWith(x => httpRes.Close(), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent);
//Matches Exceptions handled in HttpListenerBase.InitTask()
- var urlString = url.ToString();
-
task.ContinueWith(x =>
{
var statusCode = httpRes.StatusCode;
var duration = DateTime.Now - date;
- LoggerUtils.LogResponse(_logger, statusCode, urlString, remoteIp, duration);
+ if (enableLog)
+ {
+ LoggerUtils.LogResponse(_logger, statusCode, urlString, remoteIp, duration);
+ }
}, TaskContinuationOptions.None);
return task;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
index fae702023..0b8caaa6e 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
@@ -1,12 +1,31 @@
using MediaBrowser.Model.Logging;
using System;
using System.Globalization;
+using System.IO;
+using SocketHttpListener.Net;
namespace MediaBrowser.Server.Implementations.HttpServer
{
public static class LoggerUtils
{
/// <summary>
+ /// Logs the request.
+ /// </summary>
+ /// <param name="logger">The logger.</param>
+ /// <param name="request">The request.</param>
+ public static void LogRequest(ILogger logger, HttpListenerRequest request)
+ {
+ var url = request.Url.ToString();
+
+ logger.Info("{0} {1}. UserAgent: {2}", (request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod), url, request.UserAgent ?? string.Empty);
+ }
+
+ public static void LogRequest(ILogger logger, string url, string method, string userAgent)
+ {
+ logger.Info("{0} {1}. UserAgent: {2}", ("HTTP " + method), url, userAgent ?? string.Empty);
+ }
+
+ /// <summary>
/// Logs the response.
/// </summary>
/// <param name="logger">The logger.</param>
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
index a91b1e3ed..a029e0955 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
@@ -78,10 +78,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
var request = context.Request;
- LogRequest(_logger, request);
-
if (request.IsWebSocketRequest)
{
+ LoggerUtils.LogRequest(_logger, request);
+
ProcessWebSocketRequest(context);
return Task.FromResult(true);
}
@@ -156,44 +156,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
return req;
}
- /// <summary>
- /// Logs the request.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="request">The request.</param>
- private static void LogRequest(ILogger logger, HttpListenerRequest request)
- {
- var url = request.Url.ToString();
- var extension = Path.GetExtension(url);
-
- if (string.Equals(extension, ".js", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- if (string.Equals(extension, ".css", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- if (string.Equals(extension, ".woff", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- if (string.Equals(extension, ".woff2", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- if (string.Equals(extension, ".ttf", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- if (string.Equals(extension, ".html", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
-
- logger.Info("{0} {1}. UserAgent: {2}", (request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod), url, request.UserAgent ?? string.Empty);
- }
-
private void HandleError(Exception ex, HttpListenerContext context)
{
var httpReq = GetRequest(context);
diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
index 85ea8ec57..184b72d8f 100644
--- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
+++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
@@ -471,11 +471,11 @@ namespace MediaBrowser.Server.Implementations.IO
{
if (_updateTimer == null)
{
- _updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
+ _updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
}
else
{
- _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
+ _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
}
}
}
@@ -513,12 +513,18 @@ namespace MediaBrowser.Server.Implementations.IO
private bool IsFileLocked(string path)
{
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT)
+ {
+ // Causing lockups on linux
+ return false;
+ }
+
try
{
var data = _fileSystem.GetFileSystemInfo(path);
if (!data.Exists
- || data.Attributes.HasFlag(FileAttributes.Directory)
+ || data.IsDirectory
// Opening a writable stream will fail with readonly files
|| data.Attributes.HasFlag(FileAttributes.ReadOnly))
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 0cb5174c9..b0b2680ca 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -222,7 +222,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// <summary>
/// The _root folder
/// </summary>
- private AggregateFolder _rootFolder;
+ private volatile AggregateFolder _rootFolder;
/// <summary>
/// The _root folder sync lock
/// </summary>
@@ -743,7 +743,7 @@ namespace MediaBrowser.Server.Implementations.Library
return rootFolder;
}
- private UserRootFolder _userRootFolder;
+ private volatile UserRootFolder _userRootFolder;
private readonly object _syncLock = new object();
public Folder GetUserRootFolder()
{
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index 407aac53d..8beb03b71 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -51,8 +51,17 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
{
var filename = Path.GetFileNameWithoutExtension(path) ?? string.Empty;
- return !IgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase)
- && imageProcessor.SupportedInputFormats.Contains((Path.GetExtension(path) ?? string.Empty).TrimStart('.'), StringComparer.OrdinalIgnoreCase);
+ if (IgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ if (IgnoreFiles.Any(i => filename.IndexOf("-" + i, StringComparison.OrdinalIgnoreCase) != -1))
+ {
+ return false;
+ }
+
+ return imageProcessor.SupportedInputFormats.Contains((Path.GetExtension(path) ?? string.Empty).TrimStart('.'), StringComparer.OrdinalIgnoreCase);
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
index 30a720a62..0df4742bd 100644
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
@@ -163,7 +163,14 @@ namespace MediaBrowser.Server.Implementations.Library
var channels = channelResult.Items;
- list.AddRange(channels);
+ if (user.Configuration.DisplayChannelsInline && channels.Length > 0)
+ {
+ list.Add(await _channelManager.GetInternalChannelFolder(cancellationToken).ConfigureAwait(false));
+ }
+ else
+ {
+ list.AddRange(channels);
+ }
if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId))
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 356d0d83d..cd91684ce 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -22,12 +22,15 @@ using MediaBrowser.Server.Implementations.FileOrganization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Power;
+using Microsoft.Win32;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -55,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public static EmbyTV Current;
- public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder)
+ public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, IPowerManagement powerManagement)
{
Current = this;
@@ -75,13 +78,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_recordingProvider = new ItemDataProvider<RecordingInfo>(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
_seriesTimerProvider = new SeriesTimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
- _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"));
+ _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"), powerManagement, _logger);
_timerProvider.TimerFired += _timerProvider_TimerFired;
}
public void Start()
{
_timerProvider.RestartTimers();
+
+ SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
+
+ }
+
+ void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
+ {
+ _logger.Info("Power mode changed to {0}", e.Mode);
+
+ if (e.Mode == PowerModes.Resume)
+ {
+ _timerProvider.RestartTimers();
+ }
}
public event EventHandler DataSourceChanged;
@@ -155,7 +171,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
epgData = GetEpgDataForChannel(timer.ChannelId);
}
- await UpdateTimersForSeriesTimer(epgData, timer).ConfigureAwait(false);
+ await UpdateTimersForSeriesTimer(epgData, timer, false).ConfigureAwait(false);
}
var timers = await GetTimersAsync(cancellationToken).ConfigureAwait(false);
@@ -223,7 +239,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken)
{
- var timers = _timerProvider.GetAll().Where(i => string.Equals(i.SeriesTimerId, timerId, StringComparison.OrdinalIgnoreCase));
+ var timers = _timerProvider
+ .GetAll()
+ .Where(i => string.Equals(i.SeriesTimerId, timerId, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
foreach (var timer in timers)
{
CancelTimerInternal(timer.Id);
@@ -332,25 +352,44 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
_seriesTimerProvider.Add(info);
- await UpdateTimersForSeriesTimer(epgData, info).ConfigureAwait(false);
+ await UpdateTimersForSeriesTimer(epgData, info, false).ConfigureAwait(false);
}
public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
{
- _seriesTimerProvider.Update(info);
- List<ProgramInfo> epgData;
- if (info.RecordAnyChannel)
- {
- var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false);
- var channelIds = channels.Select(i => i.Id).ToList();
- epgData = GetEpgDataForChannels(channelIds);
- }
- else
+ var instance = _seriesTimerProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
+
+ if (instance != null)
{
- epgData = GetEpgDataForChannel(info.ChannelId);
- }
+ instance.ChannelId = info.ChannelId;
+ instance.Days = info.Days;
+ instance.EndDate = info.EndDate;
+ instance.IsPostPaddingRequired = info.IsPostPaddingRequired;
+ instance.IsPrePaddingRequired = info.IsPrePaddingRequired;
+ instance.PostPaddingSeconds = info.PostPaddingSeconds;
+ instance.PrePaddingSeconds = info.PrePaddingSeconds;
+ instance.Priority = info.Priority;
+ instance.RecordAnyChannel = info.RecordAnyChannel;
+ instance.RecordAnyTime = info.RecordAnyTime;
+ instance.RecordNewOnly = info.RecordNewOnly;
+ instance.StartDate = info.StartDate;
- await UpdateTimersForSeriesTimer(epgData, info).ConfigureAwait(false);
+ _seriesTimerProvider.Update(instance);
+
+ List<ProgramInfo> epgData;
+ if (instance.RecordAnyChannel)
+ {
+ var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false);
+ var channelIds = channels.Select(i => i.Id).ToList();
+ epgData = GetEpgDataForChannels(channelIds);
+ }
+ else
+ {
+ epgData = GetEpgDataForChannel(instance.ChannelId);
+ }
+
+ await UpdateTimersForSeriesTimer(epgData, instance, true).ConfigureAwait(false);
+ }
}
public Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
@@ -603,6 +642,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
await RecordStream(timer, recordingEndDate, cancellationTokenSource.Token).ConfigureAwait(false);
}
+ else
+ {
+ _logger.Info("Skipping RecordStream because it's already in progress.");
+ }
}
catch (OperationCanceledException)
{
@@ -721,7 +764,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
recording.DateLastUpdated = DateTime.UtcNow;
_recordingProvider.AddOrUpdate(recording);
- _logger.Info("Beginning recording.");
+ _logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));
httpRequestOptions.BufferContent = false;
var durationToken = new CancellationTokenSource(duration);
@@ -836,7 +879,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return _config.GetConfiguration<LiveTvOptions>("livetv");
}
- private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer)
+ private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers)
{
var newTimers = GetTimersForSeries(seriesTimer, epgData, _recordingProvider.GetAll()).ToList();
@@ -849,12 +892,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_timerProvider.AddOrUpdate(timer);
}
}
+
+ if (deleteInvalidTimers)
+ {
+ var allTimers = GetTimersForSeries(seriesTimer, epgData, new List<RecordingInfo>())
+ .Select(i => i.Id)
+ .ToList();
+
+ var deletes = _timerProvider.GetAll()
+ .Where(i => string.Equals(i.SeriesTimerId, seriesTimer.Id, StringComparison.OrdinalIgnoreCase))
+ .Where(i => !allTimers.Contains(i.Id, StringComparer.OrdinalIgnoreCase) && i.StartDate > DateTime.UtcNow)
+ .ToList();
+
+ foreach (var timer in deletes)
+ {
+ await CancelTimerAsync(timer.Id, CancellationToken.None).ConfigureAwait(false);
+ }
+ }
}
private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer, IEnumerable<ProgramInfo> allPrograms, IReadOnlyList<RecordingInfo> currentRecordings)
{
// Exclude programs that have already ended
- allPrograms = allPrograms.Where(i => i.EndDate > DateTime.UtcNow);
+ allPrograms = allPrograms.Where(i => i.EndDate > DateTime.UtcNow && i.StartDate > DateTime.UtcNow);
allPrograms = GetProgramsForSeries(seriesTimer, allPrograms);
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index f46daa6d5..b29a7562c 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 List<T> _items;
+ private volatile List<T> _items;
private readonly IJsonSerializer _jsonSerializer;
protected readonly ILogger Logger;
private readonly string _dataPath;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 80bb671fa..5d462f106 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -5,22 +5,27 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Concurrent;
+using System.Globalization;
using System.Linq;
using System.Threading;
using CommonIO;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Power;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
public class TimerManager : ItemDataProvider<TimerInfo>
{
private readonly ConcurrentDictionary<string, Timer> _timers = new ConcurrentDictionary<string, Timer>(StringComparer.OrdinalIgnoreCase);
+ private readonly IPowerManagement _powerManagement;
+ private readonly ILogger _logger;
public event EventHandler<GenericEventArgs<TimerInfo>> TimerFired;
- public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
+ public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, IPowerManagement powerManagement, ILogger logger1)
: base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
+ _powerManagement = powerManagement;
+ _logger = logger1;
}
public void RestartTimers()
@@ -58,6 +63,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var timespan = RecordingHelper.GetStartTime(item) - DateTime.UtcNow;
timer.Change(timespan, TimeSpan.Zero);
+ ScheduleWake(item);
}
else
{
@@ -74,6 +80,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
base.Add(item);
AddTimer(item);
+ ScheduleWake(item);
}
private void AddTimer(TimerInfo item)
@@ -91,15 +98,39 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
StartTimer(item, timerLength);
}
+ private void ScheduleWake(TimerInfo info)
+ {
+ var startDate = RecordingHelper.GetStartTime(info).AddMinutes(-5);
+
+ try
+ {
+ _powerManagement.ScheduleWake(startDate);
+ _logger.Info("Scheduled system wake timer at {0} (UTC)", startDate);
+ }
+ catch (NotImplementedException)
+ {
+
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error scheduling wake timer", ex);
+ }
+ }
+
public void StartTimer(TimerInfo item, TimeSpan length)
{
StopTimer(item);
var timer = new Timer(TimerCallback, item.Id, length, TimeSpan.Zero);
- if (!_timers.TryAdd(item.Id, timer))
+ if (_timers.TryAdd(item.Id, timer))
+ {
+ _logger.Info("Creating recording timer for {0}, {1}. Timer will fire in {2} minutes", item.Id, item.Name, length.TotalMinutes.ToString(CultureInfo.InvariantCulture));
+ }
+ else
{
timer.Dispose();
+ _logger.Warn("Timer already exists for item {0}", item.Id);
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index e09e06bd4..8bf1d27b8 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1954,6 +1954,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
+ _logger.Info("New recording scheduled");
}
public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ca.json b/MediaBrowser.Server.Implementations/Localization/Core/ca.json
index 40dfcd2c3..83d72030f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ca.json
@@ -1,6 +1,6 @@
{
- "AppDeviceValues": "App: {0}, Device: {1}",
- "UserDownloadingItemWithValues": "{0} is downloading {1}",
+ "AppDeviceValues": "App: {0}, Dispositiu: {1}",
+ "UserDownloadingItemWithValues": "{0} est\u00e0 descarregant {1}",
"FolderTypeMixed": "Mixed content",
"FolderTypeMovies": "Pel\u00b7l\u00edcules",
"FolderTypeMusic": "M\u00fasica",
@@ -12,10 +12,10 @@
"FolderTypeBooks": "Llibres",
"FolderTypeTvShows": "TV",
"FolderTypeInherit": "Heretat",
- "HeaderCastCrew": "Repartiment i equip",
+ "HeaderCastCrew": "Repartiment i Equip",
"HeaderPeople": "People",
"ValueSpecialEpisodeName": "Special - {0}",
- "LabelChapterName": "Chapter {0}",
+ "LabelChapterName": "Cap\u00edtol {0}",
"NameSeasonNumber": "Temporada {0}",
"LabelExit": "Sortir",
"LabelVisitCommunity": "Visita la comunitat",
@@ -77,7 +77,7 @@
"ViewTypeMovieMovies": "Pel\u00b7l\u00edcules",
"ViewTypeMovieCollections": "Col\u00b7leccions",
"ViewTypeMovieFavorites": "Preferides",
- "ViewTypeMovieGenres": "Genres",
+ "ViewTypeMovieGenres": "G\u00e8neres",
"ViewTypeMusicLatest": "Novetats",
"ViewTypeMusicPlaylists": "Llistes de reproducci\u00f3",
"ViewTypeMusicAlbums": "\u00c0lbums",
@@ -89,7 +89,7 @@
"ViewTypeMusicFavoriteArtists": "Artistes Preferits",
"ViewTypeMusicFavoriteSongs": "Can\u00e7ons Preferides",
"ViewTypeFolders": "Directoris",
- "ViewTypeLiveTvRecordingGroups": "Recordings",
+ "ViewTypeLiveTvRecordingGroups": "Enregistraments",
"ViewTypeLiveTvChannels": "Canals",
"ScheduledTaskFailedWithName": "{0} failed",
"LabelRunningTimeValue": "Running time: {0}",
@@ -103,7 +103,7 @@
"LabelIpAddressValue": "Ip address: {0}",
"DeviceOnlineWithName": "{0} is connected",
"UserOnlineFromDevice": "{0} is online from {1}",
- "ProviderValue": "Provider: {0}",
+ "ProviderValue": "Prove\u00efdor: {0}",
"SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
"UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
"UserCreatedWithName": "User {0} has been created",
@@ -113,12 +113,12 @@
"MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
"MessageApplicationUpdated": "Emby Server has been updated",
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
- "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
+ "AuthenticationSucceededWithUserName": "{0} autenticat correctament",
"DeviceOfflineWithName": "{0} has disconnected",
"UserLockedOutWithName": "User {0} has been locked out",
"UserOfflineFromDevice": "{0} has disconnected from {1}",
- "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
- "UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
+ "UserStartedPlayingItemWithValues": "{0} ha comen\u00e7at a reproduir {1}",
+ "UserStoppedPlayingItemWithValues": "{0} ha parat de reproduir {1}",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
"HeaderUnidentified": "Unidentified",
"HeaderImagePrimary": "Primary",
@@ -164,7 +164,7 @@
"HeaderTracks": "Tracks",
"HeaderMusicArtist": "M\u00fasic",
"HeaderLocked": "Locked",
- "HeaderStudios": "Studios",
+ "HeaderStudios": "Estudis",
"HeaderActor": "Actors",
"HeaderComposer": "Compositors",
"HeaderDirector": "Directors",
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/nl.json b/MediaBrowser.Server.Implementations/Localization/Core/nl.json
index b32ebefc3..fd0c586a2 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/nl.json
@@ -63,7 +63,7 @@
"ViewTypeLatestGames": "Nieuwste games",
"ViewTypeRecentlyPlayedGames": "Recent gespeelt",
"ViewTypeGameFavorites": "Favorieten",
- "ViewTypeGameSystems": "Gam systemen",
+ "ViewTypeGameSystems": "Game systemen",
"ViewTypeGameGenres": "Genres",
"ViewTypeTvResume": "Hervatten",
"ViewTypeTvNextUp": "Volgende",
@@ -147,7 +147,7 @@
"HeaderCommunityRating": "Gemeenschap cijfer",
"HeaderTrailers": "Trailers",
"HeaderSpecials": "Specials",
- "HeaderGameSystems": "Spel systemen",
+ "HeaderGameSystems": "Game systemen",
"HeaderPlayers": "Spelers:",
"HeaderAlbumArtists": "Album artiesten",
"HeaderAlbums": "Albums",
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index e5c94a01b..c54ea42a5 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -48,9 +48,9 @@
<Reference Include="Interfaces.IO">
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
</Reference>
- <Reference Include="MediaBrowser.Naming, Version=1.0.5818.23111, Culture=neutral, processorArchitecture=MSIL">
+ <Reference Include="MediaBrowser.Naming, Version=1.0.5869.26812, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\MediaBrowser.Naming.1.0.0.41\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
+ <HintPath>..\packages\MediaBrowser.Naming.1.0.0.44\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
</Reference>
<Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
diff --git a/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs b/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs
index e8f910f81..969541fbc 100644
--- a/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs
@@ -1,6 +1,5 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Notifications;
@@ -17,12 +16,13 @@ using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using CommonIO;
+using MediaBrowser.Common.Threading;
namespace MediaBrowser.Server.Implementations.News
{
public class NewsEntryPoint : IServerEntryPoint
{
- private Timer _timer;
+ private PeriodicTimer _timer;
private readonly IHttpClient _httpClient;
private readonly IApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem;
@@ -47,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.News
public void Run()
{
- _timer = new Timer(OnTimerFired, null, TimeSpan.FromMilliseconds(500), _frequency);
+ _timer = new PeriodicTimer(OnTimerFired, null, TimeSpan.FromMilliseconds(500), _frequency);
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index 5c04f2782..b7f5533ce 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -2,7 +2,7 @@
<packages>
<package id="CommonIO" version="1.0.0.7" targetFramework="net45" />
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
- <package id="MediaBrowser.Naming" version="1.0.0.41" targetFramework="net45" />
+ <package id="MediaBrowser.Naming" version="1.0.0.44" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
diff --git a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
index 31d4592c8..e57a651c0 100644
--- a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
+++ b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
@@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
+using MediaBrowser.Controller.Power;
namespace MediaBrowser.Server.Mono.Native
{
@@ -203,5 +204,18 @@ namespace MediaBrowser.Server.Mono.Native
public string sysname = string.Empty;
public string machine = string.Empty;
}
+
+ public IPowerManagement GetPowerManagement()
+ {
+ return new NullPowerManagement();
+ }
+ }
+
+ public class NullPowerManagement : IPowerManagement
+ {
+ public void ScheduleWake(DateTime utcTime)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index 21731a3a6..2d625f810 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -210,7 +210,6 @@ namespace MediaBrowser.Server.Startup.Common
private readonly string _releaseAssetFilename;
internal INativeApp NativeApp { get; set; }
- private Timer _ipAddressCacheTimer;
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationHost" /> class.
@@ -234,8 +233,6 @@ namespace MediaBrowser.Server.Startup.Common
NativeApp = nativeApp;
SetBaseExceptionMessage();
-
- _ipAddressCacheTimer = new Timer(OnCacheClearTimerFired, null, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3));
}
private Version _version;
@@ -533,6 +530,8 @@ namespace MediaBrowser.Server.Startup.Common
EncodingManager = new EncodingManager(FileSystemManager, Logger, MediaEncoder, ChapterManager);
RegisterSingleInstance(EncodingManager);
+ RegisterSingleInstance(NativeApp.GetPowerManagement());
+
var sharingRepo = new SharingRepository(LogManager, ApplicationPaths);
await sharingRepo.Initialize().ConfigureAwait(false);
RegisterSingleInstance<ISharingManager>(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this));
@@ -970,10 +969,10 @@ namespace MediaBrowser.Server.Startup.Common
{
get
{
- if (!ServerConfigurationManager.Configuration.EnableAutoUpdate)
- {
- return false;
- }
+ if (!ServerConfigurationManager.Configuration.EnableAutoUpdate)
+ {
+ return false;
+ }
#if DEBUG
return false;
#endif
@@ -1157,8 +1156,13 @@ namespace MediaBrowser.Server.Startup.Common
}
private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
+ private DateTime _lastAddressCacheClear;
private bool IsIpAddressValid(IPAddress address)
{
+ return IsIpAddressValidInternal(address).Result;
+ }
+ private async Task<bool> IsIpAddressValidInternal(IPAddress address)
+ {
if (IPAddress.IsLoopback(address))
{
return true;
@@ -1167,6 +1171,12 @@ namespace MediaBrowser.Server.Startup.Common
var apiUrl = GetLocalApiUrl(address.ToString());
apiUrl += "/system/ping";
+ if ((DateTime.UtcNow - _lastAddressCacheClear).TotalMinutes >= 5)
+ {
+ _lastAddressCacheClear = DateTime.UtcNow;
+ _validAddressResults.Clear();
+ }
+
bool cachedResult;
if (_validAddressResults.TryGetValue(apiUrl, out cachedResult))
{
@@ -1175,14 +1185,15 @@ namespace MediaBrowser.Server.Startup.Common
try
{
- using (var response = HttpClient.SendAsync(new HttpRequestOptions
+ using (var response = await HttpClient.SendAsync(new HttpRequestOptions
{
Url = apiUrl,
LogErrorResponseBody = false,
LogErrors = false,
- LogRequest = false
+ LogRequest = false,
+ TimeoutMs = 30000
- }, "POST").Result)
+ }, "POST").ConfigureAwait(false))
{
using (var reader = new StreamReader(response.Content))
{
@@ -1190,25 +1201,20 @@ namespace MediaBrowser.Server.Startup.Common
var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
_validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
- Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, valid);
+ //Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, valid);
return valid;
}
}
}
catch
{
- Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, false);
+ //Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, false);
_validAddressResults.AddOrUpdate(apiUrl, false, (k, v) => false);
return false;
}
}
- private void OnCacheClearTimerFired(object state)
- {
- _validAddressResults.Clear();
- }
-
public string FriendlyName
{
get
diff --git a/MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs b/MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs
index ba335868d..20d4c6b2a 100644
--- a/MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs
+++ b/MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs
@@ -4,7 +4,7 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Logging;
using System;
using System.Linq;
-using System.Threading;
+using MediaBrowser.Common.Threading;
namespace MediaBrowser.Server.Startup.Common.EntryPoints
{
@@ -12,7 +12,7 @@ namespace MediaBrowser.Server.Startup.Common.EntryPoints
{
private readonly ISessionManager _sessionManager;
private readonly ILogger _logger;
- private Timer _timer;
+ private PeriodicTimer _timer;
private readonly IServerApplicationHost _appHost;
public KeepServerAwake(ISessionManager sessionManager, ILogger logger, IServerApplicationHost appHost)
@@ -24,7 +24,7 @@ namespace MediaBrowser.Server.Startup.Common.EntryPoints
public void Run()
{
- _timer = new Timer(obj =>
+ _timer = new PeriodicTimer(obj =>
{
var now = DateTime.UtcNow;
if (_sessionManager.Sessions.Any(i => (now - i.LastActivityDate).TotalMinutes < 15))
diff --git a/MediaBrowser.Server.Startup.Common/INativeApp.cs b/MediaBrowser.Server.Startup.Common/INativeApp.cs
index 597caf34c..75b38d0c4 100644
--- a/MediaBrowser.Server.Startup.Common/INativeApp.cs
+++ b/MediaBrowser.Server.Startup.Common/INativeApp.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Model.Logging;
using System.Collections.Generic;
using System.Reflection;
+using MediaBrowser.Controller.Power;
namespace MediaBrowser.Server.Startup.Common
{
@@ -90,5 +91,11 @@ namespace MediaBrowser.Server.Startup.Common
/// Prevents the system stand by.
/// </summary>
void PreventSystemStandby();
+
+ /// <summary>
+ /// Gets the power management.
+ /// </summary>
+ /// <returns>IPowerManagement.</returns>
+ IPowerManagement GetPowerManagement();
}
}
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index 62cdbd05f..cf174c2d3 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -218,7 +218,7 @@ namespace MediaBrowser.ServerApplication
var fileSystem = new WindowsFileSystem(new PatternsLogger(logManager.GetLogger("FileSystem")));
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
- var nativeApp = new WindowsApp(fileSystem)
+ var nativeApp = new WindowsApp(fileSystem, _logger)
{
IsRunningAsService = runService
};
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index c62983192..80e56d6e1 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -120,6 +120,7 @@
<Compile Include="Native\Standby.cs" />
<Compile Include="Native\ServerAuthorization.cs" />
<Compile Include="Native\WindowsApp.cs" />
+ <Compile Include="Native\WindowsPowerManagement.cs" />
<Compile Include="Networking\CertificateGenerator.cs" />
<Compile Include="Networking\NativeMethods.cs" />
<Compile Include="Networking\NetworkManager.cs" />
diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
index ceab5379d..fe2fe6de6 100644
--- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs
+++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
@@ -6,16 +6,19 @@ using MediaBrowser.ServerApplication.Networking;
using System.Collections.Generic;
using System.Reflection;
using CommonIO;
+using MediaBrowser.Controller.Power;
namespace MediaBrowser.ServerApplication.Native
{
public class WindowsApp : INativeApp
{
private readonly IFileSystem _fileSystem;
+ private readonly ILogger _logger;
- public WindowsApp(IFileSystem fileSystem)
+ public WindowsApp(IFileSystem fileSystem, ILogger logger)
{
_fileSystem = fileSystem;
+ _logger = logger;
}
public List<Assembly> GetAssembliesWithParts()
@@ -117,5 +120,10 @@ namespace MediaBrowser.ServerApplication.Native
{
Standby.PreventSystemStandby();
}
+
+ public IPowerManagement GetPowerManagement()
+ {
+ return new WindowsPowerManagement(_logger);
+ }
}
}
diff --git a/MediaBrowser.ServerApplication/Native/WindowsPowerManagement.cs b/MediaBrowser.ServerApplication/Native/WindowsPowerManagement.cs
new file mode 100644
index 000000000..866272639
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/WindowsPowerManagement.cs
@@ -0,0 +1,94 @@
+using System;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.Threading;
+using MediaBrowser.Controller.Power;
+using MediaBrowser.Model.Logging;
+using Microsoft.Win32.SafeHandles;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ public class WindowsPowerManagement : IPowerManagement
+ {
+ [DllImport("kernel32.dll")]
+ public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes,
+ bool bManualReset,
+ string lpTimerName);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetWaitableTimer(SafeWaitHandle hTimer,
+ [In] ref long pDueTime,
+ int lPeriod,
+ IntPtr pfnCompletionRoutine,
+ IntPtr lpArgToCompletionRoutine,
+ bool fResume);
+
+ private BackgroundWorker _bgWorker;
+ private readonly ILogger _logger;
+ private readonly object _initLock = new object();
+
+ public WindowsPowerManagement(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public void ScheduleWake(DateTime utcTime)
+ {
+ //Initialize();
+ //_bgWorker.RunWorkerAsync(utcTime.ToFileTime());
+ throw new NotImplementedException();
+ }
+
+ private void Initialize()
+ {
+ lock (_initLock)
+ {
+ if (_bgWorker == null)
+ {
+ _bgWorker = new BackgroundWorker();
+
+ _bgWorker.DoWork += bgWorker_DoWork;
+ _bgWorker.RunWorkerCompleted += bgWorker_RunWorkerCompleted;
+ }
+ }
+ }
+
+ void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+ {
+ //if (Woken != null)
+ //{
+ // Woken(this, new EventArgs());
+ //}
+ }
+
+ private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
+ {
+ try
+ {
+ long waketime = (long)e.Argument;
+
+ using (SafeWaitHandle handle = CreateWaitableTimer(IntPtr.Zero, true, GetType().Assembly.GetName().Name + "Timer"))
+ {
+ if (SetWaitableTimer(handle, ref waketime, 0, IntPtr.Zero, IntPtr.Zero, true))
+ {
+ using (EventWaitHandle wh = new EventWaitHandle(false,
+ EventResetMode.AutoReset))
+ {
+ wh.SafeWaitHandle = handle;
+ wh.WaitOne();
+ }
+ }
+ else
+ {
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error scheduling wake timer", ex);
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 5ad40e4c7..12cd5c385 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -354,8 +354,7 @@ namespace MediaBrowser.WebDashboard.Api
DeleteFoldersByName(Path.Combine(bowerPath, "jstree"), "src");
DeleteFoldersByName(Path.Combine(bowerPath, "Sortable"), "meteor");
DeleteFoldersByName(Path.Combine(bowerPath, "Sortable"), "st");
- DeleteFoldersByName(Path.Combine(bowerPath, "swipebox"), "lib");
- DeleteFoldersByName(Path.Combine(bowerPath, "swipebox"), "scss");
+ DeleteFoldersByName(Path.Combine(bowerPath, "Swiper"), "src");
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
{
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index cc153a010..165792291 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -158,9 +158,6 @@
<Content Include="dashboard-ui\components\metadataeditor\metadataeditor.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\paperdialoghelper.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\components\playlisteditor\playlisteditor.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -311,9 +308,6 @@
<Content Include="dashboard-ui\scripts\supporterkeypage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\testermessage.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\wizardlivetvguide.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index c5184ec3d..40b974ee7 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -215,7 +215,11 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val))
{
DateTime added;
- if (DateTime.TryParse(val, out added))
+ if (DateTime.TryParseExact(val, BaseNfoSaver.DateAddedFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out added))
+ {
+ item.EndDate = added.ToUniversalTime();
+ }
+ else if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out added))
{
item.DateCreated = added.ToUniversalTime();
}
@@ -627,7 +631,10 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
var person = GetPersonFromXmlNode(subtree);
- itemResult.AddPerson(person);
+ if (!string.IsNullOrWhiteSpace(person.Name))
+ {
+ itemResult.AddPerson(person);
+ }
}
break;
}
@@ -976,11 +983,11 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val) && !string.IsNullOrWhiteSpace(userDataUserId))
{
DateTime parsedValue;
- if (DateTime.TryParseExact(val, "yyyy-MM-dd HH:mm:ss", _usCulture, DateTimeStyles.None, out parsedValue))
+ if (DateTime.TryParseExact(val, "yyyy-MM-dd HH:mm:ss", _usCulture, DateTimeStyles.AssumeLocal, out parsedValue))
{
var userData = GetOrAdd(itemResult, userDataUserId);
- userData.LastPlayedDate = parsedValue;
+ userData.LastPlayedDate = parsedValue.ToUniversalTime();
}
}
break;
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 0da53f575..c114f9dd9 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -416,6 +416,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteEndElement();
}
+ public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss";
+
/// <summary>
/// Adds the common nodes.
/// </summary>
@@ -472,7 +474,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("type", item.DisplayMediaType);
}
- writer.WriteElementString("dateadded", item.DateCreated.ToString("yyyy-MM-dd HH:mm:ss"));
+ writer.WriteElementString("dateadded", item.DateCreated.ToLocalTime().ToString(DateAddedFormat));
writer.WriteElementString("title", item.Name ?? string.Empty);
writer.WriteElementString("originaltitle", item.Name ?? string.Empty);
@@ -949,7 +951,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (userdata.LastPlayedDate.HasValue)
{
- writer.WriteElementString("lastplayed", userdata.LastPlayedDate.Value.ToString("yyyy-MM-dd HH:mm:ss").ToLower());
+ writer.WriteElementString("lastplayed", userdata.LastPlayedDate.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss").ToLower());
}
writer.WriteStartElement("resume");