Merge pull request #2347 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2016-12-17 21:35:57 -05:00 committed by GitHub
commit 03acdc7cc9
8 changed files with 486 additions and 130 deletions

View file

@ -488,20 +488,17 @@ namespace Emby.Common.Implementations.IO
}
var temp1 = Path.GetTempFileName();
var temp2 = Path.GetTempFileName();
// Copying over will fail against hidden files
RemoveHiddenAttribute(file1);
RemoveHiddenAttribute(file2);
CopyFile(file1, temp1, true);
CopyFile(file2, temp2, true);
CopyFile(file2, file1, true);
CopyFile(temp1, file2, true);
CopyFile(temp2, file1, true);
DeleteFile(temp1);
DeleteFile(temp2);
}
/// <summary>

View file

@ -1,8 +1,10 @@
using System;
using System.IO;
using System.Linq;
using System.Xml;
using NLog;
using NLog.Config;
using NLog.Filters;
using NLog.Targets;
using NLog.Targets.Wrappers;
using MediaBrowser.Model.Logging;
@ -14,20 +16,35 @@ namespace Emby.Common.Implementations.Logging
/// </summary>
public class NlogManager : ILogManager
{
/// <summary>
/// Occurs when [logger loaded].
/// </summary>
public event EventHandler LoggerLoaded;
#region Private Fields
private LogSeverity _severity = LogSeverity.Debug;
/// <summary>
/// Gets or sets the log directory.
/// </summary>
/// <value>The log directory.</value>
private string LogDirectory { get; set; }
private readonly string LogDirectory;
/// <summary>
/// Gets or sets the log file prefix.
/// </summary>
/// <value>The log file prefix.</value>
private string LogFilePrefix { get; set; }
private readonly string LogFilePrefix;
#endregion
#region Event Declarations
/// <summary>
/// Occurs when [logger loaded].
/// </summary>
public event EventHandler LoggerLoaded;
#endregion
#region Public Properties
/// <summary>
/// Gets the log file path.
/// </summary>
@ -40,28 +57,25 @@ namespace Emby.Common.Implementations.Logging
/// <value>The exception message prefix.</value>
public string ExceptionMessagePrefix { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="NlogManager" /> class.
/// </summary>
/// <param name="logDirectory">The log directory.</param>
/// <param name="logFileNamePrefix">The log file name prefix.</param>
public NlogManager(string logDirectory, string logFileNamePrefix)
{
LogDirectory = logDirectory;
LogFilePrefix = logFileNamePrefix;
public string NLogConfigurationFilePath { get; set; }
LogManager.Configuration = new LoggingConfiguration ();
}
private LogSeverity _severity = LogSeverity.Debug;
public LogSeverity LogSeverity
{
get
{
return _severity;
}
set
{
DebugFileWriter(
LogDirectory, String.Format(
"SET LogSeverity, _severity = [{0}], value = [{1}]",
_severity.ToString(),
value.ToString()
));
var changed = _severity != value;
_severity = value;
@ -70,31 +84,57 @@ namespace Emby.Common.Implementations.Logging
{
UpdateLogLevel(value);
}
}
}
private void UpdateLogLevel(LogSeverity newLevel)
#endregion
#region Constructor(s)
/// <summary>
/// Initializes a new instance of the <see cref="NlogManager" /> class.
/// </summary>
/// <param name="logDirectory">The log directory.</param>
/// <param name="logFileNamePrefix">The log file name prefix.</param>
public NlogManager(string logDirectory, string logFileNamePrefix)
{
var level = GetLogLevel(newLevel);
DebugFileWriter(
logDirectory, String.Format(
"NlogManager constructor called, logDirectory is [{0}], logFileNamePrefix is [{1}], _severity is [{2}].",
logDirectory,
logFileNamePrefix,
_severity.ToString()
));
var rules = LogManager.Configuration.LoggingRules;
LogDirectory = logDirectory;
LogFilePrefix = logFileNamePrefix;
foreach (var rule in rules)
{
if (!rule.IsLoggingEnabledForLevel(level))
{
rule.EnableLoggingForLevel(level);
}
foreach (var lev in rule.Levels.ToArray())
{
if (lev < level)
{
rule.DisableLoggingForLevel(lev);
}
}
}
LogManager.Configuration = new LoggingConfiguration();
}
/// <summary>
/// Initializes a new instance of the <see cref="NlogManager" /> class.
/// </summary>
/// <param name="logDirectory">The log directory.</param>
/// <param name="logFileNamePrefix">The log file name prefix.</param>
public NlogManager(string logDirectory, string logFileNamePrefix, LogSeverity initialSeverity) : this(logDirectory, logFileNamePrefix)
{
_severity = initialSeverity;
DebugFileWriter(
logDirectory, String.Format(
"NlogManager constructor called, logDirectory is [{0}], logFileNamePrefix is [{1}], _severity is [{2}].",
logDirectory,
logFileNamePrefix,
_severity.ToString()
));
}
#endregion
#region Private Methods
/// <summary>
/// Adds the file target.
/// </summary>
@ -102,12 +142,20 @@ namespace Emby.Common.Implementations.Logging
/// <param name="level">The level.</param>
private void AddFileTarget(string path, LogSeverity level)
{
RemoveTarget("ApplicationLogFileWrapper");
var wrapper = new AsyncTargetWrapper ();
wrapper.Name = "ApplicationLogFileWrapper";
DebugFileWriter(
LogDirectory, String.Format(
"AddFileTarget called, path = [{0}], level = [{1}].",
path,
level.ToString()
));
var logFile = new FileTarget
RemoveTarget("ApplicationLogFileWrapper");
var wrapper = new AsyncTargetWrapper();
wrapper.Name = "ApplicationLogFileWrapper";
var logFile = new FileTarget
{
FileName = path,
Layout = "${longdate} ${level} ${logger}: ${message}"
@ -115,64 +163,10 @@ namespace Emby.Common.Implementations.Logging
logFile.Name = "ApplicationLogFile";
wrapper.WrappedTarget = logFile;
wrapper.WrappedTarget = logFile;
AddLogTarget(wrapper, level);
}
/// <summary>
/// Adds the log target.
/// </summary>
/// <param name="target">The target.</param>
/// <param name="level">The level.</param>
public void AddLogTarget(Target target, LogSeverity level)
{
var config = LogManager.Configuration;
config.AddTarget(target.Name, target);
var rule = new LoggingRule("*", GetLogLevel(level), target);
config.LoggingRules.Add(rule);
LogManager.Configuration = config;
}
/// <summary>
/// Removes the target.
/// </summary>
/// <param name="name">The name.</param>
public void RemoveTarget(string name)
{
var config = LogManager.Configuration;
var target = config.FindTargetByName(name);
if (target != null)
{
foreach (var rule in config.LoggingRules.ToList())
{
var contains = rule.Targets.Contains(target);
rule.Targets.Remove(target);
if (contains)
{
config.LoggingRules.Remove(rule);
}
}
config.RemoveTarget(name);
LogManager.Configuration = config;
}
}
/// <summary>
/// Gets the logger.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>ILogger.</returns>
public MediaBrowser.Model.Logging.ILogger GetLogger(string name)
{
return new NLogger(name, this);
}
/// <summary>
@ -200,15 +194,276 @@ namespace Emby.Common.Implementations.Logging
}
}
private void UpdateLogLevel(LogSeverity newLevel)
{
DebugFileWriter(
LogDirectory, String.Format(
"UpdateLogLevel called, newLevel = [{0}].",
newLevel.ToString()
));
var level = GetLogLevel(newLevel);
var rules = LogManager.Configuration.LoggingRules;
foreach (var rule in rules)
{
if (!rule.IsLoggingEnabledForLevel(level))
{
rule.EnableLoggingForLevel(level);
}
foreach (var lev in rule.Levels.ToArray())
{
if (lev < level)
{
rule.DisableLoggingForLevel(lev);
}
}
}
}
private void AddCustomFilters(string defaultLoggerNamePattern, LoggingRule defaultRule)
{
DebugFileWriter(
LogDirectory, String.Format(
"AddCustomFilters called, defaultLoggerNamePattern = [{0}], defaultRule.LoggerNamePattern = [{1}].",
defaultLoggerNamePattern,
defaultRule.LoggerNamePattern
));
try
{
var customConfig = new NLog.Config.XmlLoggingConfiguration(NLogConfigurationFilePath);
DebugFileWriter(
LogDirectory, String.Format(
"Custom Configuration Loaded, Rule Count = [{0}].",
customConfig.LoggingRules.Count.ToString()
));
foreach (var customRule in customConfig.LoggingRules)
{
DebugFileWriter(
LogDirectory, String.Format(
"Read Custom Rule, LoggerNamePattern = [{0}], Targets = [{1}].",
customRule.LoggerNamePattern,
string.Join(",", customRule.Targets.Select(x => x.Name).ToList())
));
if (customRule.LoggerNamePattern.Equals(defaultLoggerNamePattern))
{
if (customRule.Targets.Any((arg) => arg.Name.Equals(defaultRule.Targets.First().Name)))
{
DebugFileWriter(
LogDirectory, String.Format(
"Custom rule filters can be applied to this target, Filter Count = [{0}].",
customRule.Filters.Count.ToString()
));
foreach (ConditionBasedFilter customFilter in customRule.Filters)
{
DebugFileWriter(
LogDirectory, String.Format(
"Read Custom Filter, Filter = [{0}], Action = [{1}], Type = [{2}].",
customFilter.Condition.ToString(),
customFilter.Action.ToString(),
customFilter.GetType().ToString()
));
defaultRule.Filters.Add(customFilter);
}
}
else
{
DebugFileWriter(
LogDirectory, String.Format(
"Ignoring custom rule as [Target] does not match."
));
}
}
else
{
DebugFileWriter(
LogDirectory, String.Format(
"Ignoring custom rule as [LoggerNamePattern] does not match."
));
}
}
}
catch (Exception ex)
{
// Intentionally do nothing, prevent issues affecting normal execution.
DebugFileWriter(
LogDirectory, String.Format(
"Exception in AddCustomFilters, ex.Message = [{0}].",
ex.Message
)
);
}
}
#endregion
#region Public Methods
/// <summary>
/// Reloads the logger.
/// Gets the logger.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>ILogger.</returns>
public MediaBrowser.Model.Logging.ILogger GetLogger(string name)
{
DebugFileWriter(
LogDirectory, String.Format(
"GetLogger called, name = [{0}].",
name
));
return new NLogger(name, this);
}
/// <summary>
/// Adds the log target.
/// </summary>
/// <param name="target">The target.</param>
/// <param name="level">The level.</param>
public void AddLogTarget(Target target, LogSeverity level)
{
DebugFileWriter(
LogDirectory, String.Format(
"AddLogTarget called, target.Name = [{0}], level = [{1}].",
target.Name,
level.ToString()
));
string loggerNamePattern = "*";
var config = LogManager.Configuration;
var rule = new LoggingRule(loggerNamePattern, GetLogLevel(level), target);
config.AddTarget(target.Name, target);
AddCustomFilters(loggerNamePattern, rule);
config.LoggingRules.Add(rule);
LogManager.Configuration = config;
}
/// <summary>
/// Removes the target.
/// </summary>
/// <param name="name">The name.</param>
public void RemoveTarget(string name)
{
DebugFileWriter(
LogDirectory, String.Format(
"RemoveTarget called, name = [{0}].",
name
));
var config = LogManager.Configuration;
var target = config.FindTargetByName(name);
if (target != null)
{
foreach (var rule in config.LoggingRules.ToList())
{
var contains = rule.Targets.Contains(target);
rule.Targets.Remove(target);
if (contains)
{
config.LoggingRules.Remove(rule);
}
}
config.RemoveTarget(name);
LogManager.Configuration = config;
}
}
public void AddConsoleOutput()
{
DebugFileWriter(
LogDirectory, String.Format(
"AddConsoleOutput called."
));
RemoveTarget("ConsoleTargetWrapper");
var wrapper = new AsyncTargetWrapper();
wrapper.Name = "ConsoleTargetWrapper";
var target = new ConsoleTarget()
{
Layout = "${level}, ${logger}, ${message}",
Error = false
};
target.Name = "ConsoleTarget";
wrapper.WrappedTarget = target;
AddLogTarget(wrapper, LogSeverity);
}
public void RemoveConsoleOutput()
{
DebugFileWriter(
LogDirectory, String.Format(
"RemoveConsoleOutput called."
));
RemoveTarget("ConsoleTargetWrapper");
}
/// <summary>
/// Reloads the logger, maintaining the current log level.
/// </summary>
public void ReloadLogger()
{
ReloadLogger(LogSeverity);
}
/// <summary>
/// Reloads the logger, using the specified logging level.
/// </summary>
/// <param name="level">The level.</param>
public void ReloadLogger(LogSeverity level)
{
DebugFileWriter(
LogDirectory, String.Format(
"ReloadLogger called, level = [{0}], LogFilePath (existing) = [{1}].",
level.ToString(),
LogFilePath
));
LogFilePath = Path.Combine(LogDirectory, LogFilePrefix + "-" + decimal.Floor(DateTime.Now.Ticks / 10000000) + ".txt");
Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath));
Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath));
AddFileTarget(LogFilePath, level);
@ -218,7 +473,14 @@ namespace Emby.Common.Implementations.Logging
{
try
{
DebugFileWriter(
LogDirectory, String.Format(
"ReloadLogger called, raised event LoggerLoaded."
));
LoggerLoaded(this, EventArgs.Empty);
}
catch (Exception ex)
{
@ -232,33 +494,51 @@ namespace Emby.Common.Implementations.Logging
/// </summary>
public void Flush()
{
DebugFileWriter(
LogDirectory, String.Format(
"Flush called."
));
LogManager.Flush();
}
#endregion
public void AddConsoleOutput()
#region Conditional Debug Methods
/// <summary>
/// DEBUG: Standalone method to write out debug to assist with logger development/troubleshooting.
/// <list type="bullet">
/// <item><description>The output file will be written to the server's log directory.</description></item>
/// <item><description>Calls to the method are safe and will never throw any exceptions.</description></item>
/// <item><description>Method calls will be omitted unless the library is compiled with DEBUG defined.</description></item>
/// </list>
/// </summary>
private static void DebugFileWriter(string logDirectory, string message)
{
RemoveTarget("ConsoleTargetWrapper");
var wrapper = new AsyncTargetWrapper ();
wrapper.Name = "ConsoleTargetWrapper";
var target = new ConsoleTarget()
#if DEBUG
try
{
Layout = "${level}, ${logger}, ${message}",
Error = false
};
target.Name = "ConsoleTarget";
System.IO.File.AppendAllText(
Path.Combine(logDirectory, "NlogManager.txt"),
String.Format(
"{0} : {1}{2}",
System.DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
message,
System.Environment.NewLine
)
);
wrapper.WrappedTarget = target;
AddLogTarget(wrapper, LogSeverity);
}
public void RemoveConsoleOutput()
{
RemoveTarget("ConsoleTargetWrapper");
}
catch (Exception ex)
{
// Intentionally do nothing, prevent issues affecting normal execution.
}
#endif
}
#endregion
}
}
}

View file

@ -238,7 +238,7 @@ namespace Emby.Server.Core.EntryPoints
}
catch (Exception ex)
{
_logger.ErrorException("Error creating port map", ex);
_logger.Error("Error creating port map: " + ex.Message);
}
}

View file

@ -30,6 +30,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
Priority = seriesTimer.Priority,
Name = parent.Name,
Overview = parent.Overview,
SeriesId = parent.SeriesId,
SeriesTimerId = seriesTimer.Id,
ShowId = parent.ShowId
};
@ -63,6 +64,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
timerInfo.ShortOverview = programInfo.ShortOverview;
timerInfo.OfficialRating = programInfo.OfficialRating;
timerInfo.IsRepeat = programInfo.IsRepeat;
timerInfo.SeriesId = programInfo.SeriesId;
}
public static string GetRecordingName(TimerInfo info)

View file

@ -14,6 +14,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Dto;
namespace Emby.Server.Implementations.LiveTv
{
@ -80,6 +81,11 @@ namespace Emby.Server.Implementations.LiveTv
}
dto.ProgramInfo.SeriesTimerId = dto.SeriesTimerId;
if (!string.IsNullOrWhiteSpace(info.SeriesTimerId))
{
FillImages(dto.ProgramInfo, info.Name, info.SeriesId);
}
}
if (channel != null)
@ -131,17 +137,17 @@ namespace Emby.Server.Implementations.LiveTv
dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days);
FillImages(dto, info);
FillImages(dto, info.Name, info.SeriesId);
return dto;
}
private void FillImages(SeriesTimerInfoDto dto, SeriesTimerInfo info)
private void FillImages(BaseItemDto dto, string seriesName, string programSeriesId)
{
var librarySeries = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new string[] { typeof(Series).Name },
Name = info.Name,
Name = seriesName,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Thumb }
@ -163,12 +169,68 @@ namespace Emby.Server.Implementations.LiveTv
}
}
if (!string.IsNullOrWhiteSpace(info.SeriesId))
if (!string.IsNullOrWhiteSpace(programSeriesId))
{
var program = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
ExternalSeriesId = info.SeriesId,
ExternalSeriesId = programSeriesId,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary }
}).FirstOrDefault();
if (program != null)
{
var image = program.GetImageInfo(ImageType.Primary, 0);
if (image != null)
{
try
{
dto.ParentPrimaryImageTag = _imageProcessor.GetImageCacheTag(program, image);
dto.ParentPrimaryImageItemId = program.Id.ToString("N");
}
catch (Exception ex)
{
}
}
}
}
}
private void FillImages(SeriesTimerInfoDto dto, string seriesName, string programSeriesId)
{
var librarySeries = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new string[] { typeof(Series).Name },
Name = seriesName,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Thumb }
}).FirstOrDefault();
if (librarySeries != null)
{
var image = librarySeries.GetImageInfo(ImageType.Thumb, 0);
if (image != null)
{
try
{
dto.ParentThumbImageTag = _imageProcessor.GetImageCacheTag(librarySeries, image);
dto.ParentThumbItemId = librarySeries.Id.ToString("N");
}
catch (Exception ex)
{
}
}
}
if (!string.IsNullOrWhiteSpace(programSeriesId))
{
var program = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
ExternalSeriesId = programSeriesId,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary }

View file

@ -42,7 +42,8 @@ namespace Emby.Server.Implementations.Updates
/// </summary>
private ConcurrentBag<InstallationInfo> CompletedInstallationsInternal { get; set; }
public IEnumerable<InstallationInfo> CompletedInstallations {
public IEnumerable<InstallationInfo> CompletedInstallations
{
get { return CompletedInstallationsInternal; }
}
@ -163,8 +164,8 @@ namespace Emby.Server.Implementations.Updates
{
var data = new Dictionary<string, string>
{
{ "key", _securityManager.SupporterKey },
{ "mac", _applicationHost.SystemId },
{ "key", _securityManager.SupporterKey },
{ "mac", _applicationHost.SystemId },
{ "systemid", _applicationHost.SystemId }
};
@ -656,6 +657,8 @@ namespace Emby.Server.Implementations.Updates
// Remove it the quick way for now
_applicationHost.RemovePlugin(plugin);
_logger.Info("Deleting plugin file {0}", plugin.AssemblyFilePath);
_fileSystem.DeleteFile(plugin.AssemblyFilePath);
OnPluginUninstalled(plugin);

View file

@ -103,6 +103,16 @@ namespace MediaBrowser.Controller.Entities
}
}
public override bool CanDelete()
{
if (IsRoot)
{
return false;
}
return base.CanDelete();
}
public override bool RequiresRefresh()
{
var baseResult = base.RequiresRefresh();

View file

@ -46,6 +46,8 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
public string Overview { get; set; }
public string SeriesId { get; set; }
/// <summary>
/// The start date of the recording, in UTC.
/// </summary>