mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 03:26:07 +02:00
commit
57d5423d64
21 changed files with 38 additions and 204 deletions
|
@ -112,7 +112,7 @@ namespace Emby.Dlna
|
|||
|
||||
if (profile == null)
|
||||
{
|
||||
LogUnmatchedProfile(deviceInfo);
|
||||
_logger.LogInformation("No matching device profile found. The default will need to be used. \n{@Profile}", deviceInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -122,23 +122,6 @@ namespace Emby.Dlna
|
|||
return profile;
|
||||
}
|
||||
|
||||
private void LogUnmatchedProfile(DeviceIdentification profile)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("No matching device profile found. The default will need to be used.");
|
||||
builder.Append("FriendlyName: ").AppendLine(profile.FriendlyName);
|
||||
builder.Append("Manufacturer: ").AppendLine(profile.Manufacturer);
|
||||
builder.Append("ManufacturerUrl: ").AppendLine(profile.ManufacturerUrl);
|
||||
builder.Append("ModelDescription: ").AppendLine(profile.ModelDescription);
|
||||
builder.Append("ModelName: ").AppendLine(profile.ModelName);
|
||||
builder.Append("ModelNumber: ").AppendLine(profile.ModelNumber);
|
||||
builder.Append("ModelUrl: ").AppendLine(profile.ModelUrl);
|
||||
builder.Append("SerialNumber: ").AppendLine(profile.SerialNumber);
|
||||
|
||||
_logger.LogInformation(builder.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to match a device with a profile.
|
||||
/// Rules:
|
||||
|
|
|
@ -218,11 +218,6 @@ namespace Emby.Dlna.Main
|
|||
}
|
||||
}
|
||||
|
||||
private void LogMessage(string msg)
|
||||
{
|
||||
_logger.LogDebug(msg);
|
||||
}
|
||||
|
||||
private void StartDeviceDiscovery(ISsdpCommunicationsServer communicationsServer)
|
||||
{
|
||||
try
|
||||
|
@ -272,7 +267,7 @@ namespace Emby.Dlna.Main
|
|||
Environment.OSVersion.VersionString,
|
||||
_config.GetDlnaConfiguration().SendOnlyMatchedHost)
|
||||
{
|
||||
LogFunction = LogMessage,
|
||||
LogFunction = (msg) => _logger.LogDebug("{Msg}", msg),
|
||||
SupportPnpRootDevice = false
|
||||
};
|
||||
|
||||
|
|
|
@ -134,14 +134,11 @@ namespace Emby.Server.Implementations.Dto
|
|||
var dto = GetBaseItemDtoInternal(item, options, user, owner);
|
||||
if (item is LiveTvChannel tvChannel)
|
||||
{
|
||||
var list = new List<(BaseItemDto, LiveTvChannel)>(1) { (dto, tvChannel) };
|
||||
LivetvManager.AddChannelInfo(list, options, user);
|
||||
LivetvManager.AddChannelInfo(new[] { (dto, tvChannel) }, options, user);
|
||||
}
|
||||
else if (item is LiveTvProgram)
|
||||
{
|
||||
var list = new List<(BaseItem, BaseItemDto)>(1) { (item, dto) };
|
||||
var task = LivetvManager.AddInfoToProgramDto(list, options.Fields, user);
|
||||
Task.WaitAll(task);
|
||||
LivetvManager.AddInfoToProgramDto(new[] { (item, dto) }, options.Fields, user).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
if (item is IItemByName itemByName
|
||||
|
|
|
@ -267,7 +267,7 @@ namespace Emby.Server.Implementations.IO
|
|||
if (_fileSystemWatchers.TryAdd(path, newWatcher))
|
||||
{
|
||||
newWatcher.EnableRaisingEvents = true;
|
||||
_logger.LogInformation("Watching directory " + path);
|
||||
_logger.LogInformation("Watching directory {Path}", path);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -333,8 +333,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
try
|
||||
{
|
||||
var task = BaseItem.ChannelManager.DeleteItem(item);
|
||||
Task.WaitAll(task);
|
||||
BaseItem.ChannelManager.DeleteItem(item).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
|
|
|
@ -151,7 +151,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
|||
{
|
||||
if (parser.IsMultiPart(path))
|
||||
{
|
||||
logger.LogDebug("Found multi-disc folder: " + path);
|
||||
logger.LogDebug("Found multi-disc folder: {Path}", path);
|
||||
Interlocked.Increment(ref discSubfolderCount);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -957,7 +957,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
public async Task<ILiveStream> GetChannelStreamWithDirectStreamProvider(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Streaming Channel " + channelId);
|
||||
_logger.LogInformation("Streaming Channel {Id}", channelId);
|
||||
|
||||
var result = string.IsNullOrEmpty(streamId) ?
|
||||
null :
|
||||
|
|
|
@ -87,8 +87,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
ErrorDialog = false
|
||||
};
|
||||
|
||||
var commandLineLogMessage = processStartInfo.FileName + " " + processStartInfo.Arguments;
|
||||
_logger.LogInformation(commandLineLogMessage);
|
||||
_logger.LogInformation("{Filename} {Arguments}", processStartInfo.FileName, processStartInfo.Arguments);
|
||||
|
||||
var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "record-transcode-" + Guid.NewGuid() + ".txt");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
|
||||
|
@ -97,7 +96,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
_logFileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
|
||||
|
||||
await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false);
|
||||
await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + processStartInfo.FileName + " " + processStartInfo.Arguments + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_process = new Process
|
||||
{
|
||||
|
|
|
@ -638,7 +638,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation(Name + ": Cancelling");
|
||||
_logger.LogInformation("{Name}: Cancelling", Name);
|
||||
token.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -652,16 +652,16 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation(Name + ": Waiting on Task");
|
||||
_logger.LogInformation("{Name}: Waiting on Task", Name);
|
||||
var exited = task.Wait(2000);
|
||||
|
||||
if (exited)
|
||||
{
|
||||
_logger.LogInformation(Name + ": Task exited");
|
||||
_logger.LogInformation("{Name}: Task exited", Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation(Name + ": Timed out waiting for task to stop");
|
||||
_logger.LogInformation("{Name}: Timed out waiting for task to stop", Name);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -674,7 +674,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||
{
|
||||
try
|
||||
{
|
||||
_logger.LogDebug(Name + ": Disposing CancellationToken");
|
||||
_logger.LogDebug("{Name}: Disposing CancellationToken", Name);
|
||||
token.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -571,7 +571,7 @@ namespace Emby.Server.Implementations.Updates
|
|||
?? _pluginManager.Plugins.FirstOrDefault(p => p.Name.Equals(package.Name, StringComparison.OrdinalIgnoreCase) && p.Version.Equals(package.Version));
|
||||
|
||||
await PerformPackageInstallation(package, plugin?.Manifest.Status ?? PluginStatus.Active, cancellationToken).ConfigureAwait(false);
|
||||
_logger.LogInformation(plugin == null ? "New plugin installed: {PluginName} {PluginVersion}" : "Plugin updated: {PluginName} {PluginVersion}", package.Name, package.Version);
|
||||
_logger.LogInformation("Plugin {Action}: {PluginName} {PluginVersion}", plugin == null ? "installed" : "updated", package.Name, package.Version);
|
||||
|
||||
return plugin != null;
|
||||
}
|
||||
|
|
|
@ -1391,7 +1391,7 @@ namespace Jellyfin.Api.Controllers
|
|||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Invalid HLS segment container: " + segmentFormat);
|
||||
_logger.LogError("Invalid HLS segment container: {SegmentFormat}", segmentFormat);
|
||||
}
|
||||
|
||||
var maxMuxingQueueSize = _encodingOptions.MaxMuxingQueueSize > 128
|
||||
|
|
|
@ -543,8 +543,7 @@ namespace Jellyfin.Api.Helpers
|
|||
state,
|
||||
cancellationTokenSource);
|
||||
|
||||
var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;
|
||||
_logger.LogInformation(commandLineLogMessage);
|
||||
_logger.LogInformation("{Filename} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||
|
||||
var logFilePrefix = "FFmpeg.Transcode-";
|
||||
if (state.VideoRequest != null
|
||||
|
@ -562,8 +561,9 @@ namespace Jellyfin.Api.Helpers
|
|||
// FFmpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
|
||||
Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
|
||||
|
||||
var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;
|
||||
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(request.Path + Environment.NewLine + Environment.NewLine + JsonSerializer.Serialize(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
|
||||
await logStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
await logStream.WriteAsync(commandLineLogMessageBytes, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
|
||||
process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
|
|||
}
|
||||
}
|
||||
|
||||
_logger.LogDebug("No throttle data for " + path);
|
||||
_logger.LogDebug("No throttle data for {Path}", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -425,7 +425,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
if (item.IsFileProtocol)
|
||||
{
|
||||
Logger.LogDebug("Removed item: " + item.Path);
|
||||
Logger.LogDebug("Removed item: {Path}", item.Path);
|
||||
|
||||
item.SetParent(null);
|
||||
LibraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }, this, false);
|
||||
|
@ -807,7 +807,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
if (this is not ICollectionFolder)
|
||||
{
|
||||
Logger.LogDebug("Query requires post-filtering due to LinkedChildren. Type: " + GetType().Name);
|
||||
Logger.LogDebug("{Type}: Query requires post-filtering due to LinkedChildren.", GetType().Name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,32 +100,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
/// <returns>Location of video image.</returns>
|
||||
Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, string outputExtension, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the video images on interval.
|
||||
/// </summary>
|
||||
/// <param name="inputFile">Input file.</param>
|
||||
/// <param name="container">Video container type.</param>
|
||||
/// <param name="videoStream">Media stream information.</param>
|
||||
/// <param name="mediaSource">Media source information.</param>
|
||||
/// <param name="threedFormat">Video 3D format.</param>
|
||||
/// <param name="interval">Time interval.</param>
|
||||
/// <param name="targetDirectory">Directory to write images.</param>
|
||||
/// <param name="filenamePrefix">Filename prefix to use.</param>
|
||||
/// <param name="maxWidth">Maximum width of image.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>A task.</returns>
|
||||
Task ExtractVideoImagesOnInterval(
|
||||
string inputFile,
|
||||
string container,
|
||||
MediaStream videoStream,
|
||||
MediaSourceInfo mediaSource,
|
||||
Video3DFormat? threedFormat,
|
||||
TimeSpan interval,
|
||||
string targetDirectory,
|
||||
string filenamePrefix,
|
||||
int? maxWidth,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media info.
|
||||
/// </summary>
|
||||
|
|
|
@ -149,7 +149,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
}
|
||||
else
|
||||
{
|
||||
Logger.LogWarning("Invalid Added value found: " + val);
|
||||
Logger.LogWarning("Invalid Added value found: {Value}", val);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -223,11 +223,10 @@ namespace MediaBrowser.MediaEncoding.Attachments
|
|||
|
||||
if (failed)
|
||||
{
|
||||
var msg = $"ffmpeg attachment extraction failed for {inputPath} to {outputPath}";
|
||||
_logger.LogError("ffmpeg attachment extraction failed for {InputPath} to {OutputPath}", inputPath, outputPath);
|
||||
|
||||
_logger.LogError(msg);
|
||||
|
||||
throw new InvalidOperationException(msg);
|
||||
throw new InvalidOperationException(
|
||||
string.Format(CultureInfo.InvariantCulture, "ffmpeg attachment extraction failed for {0} to {1}", inputPath, outputPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -682,11 +682,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
if (exitCode == -1 || !file.Exists || file.Length == 0)
|
||||
{
|
||||
var msg = string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputPath);
|
||||
_logger.LogError("ffmpeg image extraction failed for {Path}", inputPath);
|
||||
|
||||
_logger.LogError(msg);
|
||||
|
||||
throw new FfmpegException(msg);
|
||||
throw new FfmpegException(string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputPath));
|
||||
}
|
||||
|
||||
return tempExtractPath;
|
||||
|
@ -705,117 +703,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
return time.ToString(@"hh\:mm\:ss\.fff", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public async Task ExtractVideoImagesOnInterval(
|
||||
string inputFile,
|
||||
string container,
|
||||
MediaStream videoStream,
|
||||
MediaSourceInfo mediaSource,
|
||||
Video3DFormat? threedFormat,
|
||||
TimeSpan interval,
|
||||
string targetDirectory,
|
||||
string filenamePrefix,
|
||||
int? maxWidth,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var inputArgument = GetInputArgument(inputFile, mediaSource);
|
||||
|
||||
var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (maxWidth.HasValue)
|
||||
{
|
||||
var maxWidthParam = maxWidth.Value.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
vf += string.Format(CultureInfo.InvariantCulture, ",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(targetDirectory);
|
||||
var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg");
|
||||
|
||||
var args = string.Format(CultureInfo.InvariantCulture, "-i {0} -threads {3} -v quiet {2} -f image2 \"{1}\"", inputArgument, outputPath, vf, _threads);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(container))
|
||||
{
|
||||
var inputFormat = EncodingHelper.GetInputFormat(container);
|
||||
if (!string.IsNullOrWhiteSpace(inputFormat))
|
||||
{
|
||||
args = "-f " + inputFormat + " " + args;
|
||||
}
|
||||
}
|
||||
|
||||
var processStartInfo = new ProcessStartInfo
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
FileName = _ffmpegPath,
|
||||
Arguments = args,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
ErrorDialog = false
|
||||
};
|
||||
|
||||
_logger.LogInformation(processStartInfo.FileName + " " + processStartInfo.Arguments);
|
||||
|
||||
await _thumbnailResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
bool ranToCompletion = false;
|
||||
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = processStartInfo,
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
using (var processWrapper = new ProcessWrapper(process, this))
|
||||
{
|
||||
try
|
||||
{
|
||||
StartProcess(processWrapper);
|
||||
|
||||
// Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
|
||||
// but we still need to detect if the process hangs.
|
||||
// Making the assumption that as long as new jpegs are showing up, everything is good.
|
||||
|
||||
bool isResponsive = true;
|
||||
int lastCount = 0;
|
||||
|
||||
while (isResponsive)
|
||||
{
|
||||
if (await process.WaitForExitAsync(TimeSpan.FromSeconds(30)).ConfigureAwait(false))
|
||||
{
|
||||
ranToCompletion = true;
|
||||
break;
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var jpegCount = _fileSystem.GetFilePaths(targetDirectory)
|
||||
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
isResponsive = jpegCount > lastCount;
|
||||
lastCount = jpegCount;
|
||||
}
|
||||
|
||||
if (!ranToCompletion)
|
||||
{
|
||||
StopProcess(processWrapper, 1000);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_thumbnailResourcePool.Release();
|
||||
}
|
||||
|
||||
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
||||
|
||||
if (exitCode == -1)
|
||||
{
|
||||
var msg = string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputArgument);
|
||||
|
||||
_logger.LogError(msg);
|
||||
|
||||
throw new FfmpegException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StartProcess(ProcessWrapper process)
|
||||
{
|
||||
process.Process.Start();
|
||||
|
|
|
@ -636,17 +636,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||
|
||||
if (failed)
|
||||
{
|
||||
var msg = $"ffmpeg subtitle extraction failed for {inputPath} to {outputPath}";
|
||||
_logger.LogError("ffmpeg subtitle extraction failed for {InputPath} to {OutputPath}", inputPath, outputPath);
|
||||
|
||||
_logger.LogError(msg);
|
||||
|
||||
throw new FfmpegException(msg);
|
||||
throw new FfmpegException(
|
||||
string.Format(CultureInfo.InvariantCulture, "ffmpeg subtitle extraction failed for {0} to {1}", inputPath, outputPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
var msg = $"ffmpeg subtitle extraction completed for {inputPath} to {outputPath}";
|
||||
|
||||
_logger.LogInformation(msg);
|
||||
_logger.LogInformation("ffmpeg subtitle extraction completed for {InputPath} to {OutputPath}", inputPath, outputPath);
|
||||
}
|
||||
|
||||
if (string.Equals(outputCodec, "ass", StringComparison.OrdinalIgnoreCase))
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|||
}
|
||||
else
|
||||
{
|
||||
Logger.LogInformation("Unrecognized series status: " + status);
|
||||
Logger.LogInformation("Unrecognized series status: {Status}", status);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,9 +44,13 @@
|
|||
<Rule Id="CA1725" Action="Error" />
|
||||
<!-- error on CA1725: Call async methods when in an async method -->
|
||||
<Rule Id="CA1727" Action="Error" />
|
||||
<!-- error on CA1843: Do not use 'WaitAll' with a single task -->
|
||||
<Rule Id="CA1843" Action="Error" />
|
||||
<!-- error on CA2016: Forward the CancellationToken parameter to methods that take one
|
||||
or pass in 'CancellationToken.None' explicitly to indicate intentionally not propagating the token -->
|
||||
<Rule Id="CA2016" Action="Error" />
|
||||
<!-- error on CA2254: Template should be a static expression -->
|
||||
<Rule Id="CA2254" Action="Error" />
|
||||
|
||||
<!-- disable warning CA1014: Mark assemblies with CLSCompliantAttribute -->
|
||||
<Rule Id="CA1014" Action="Info" />
|
||||
|
|
Loading…
Reference in a new issue