Merge remote-tracking branch 'upstream/master' into random

This commit is contained in:
Bond-009
2019-12-06 12:06:13 +01:00
339 changed files with 4276 additions and 4900 deletions

View File

@@ -13,7 +13,6 @@ using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
@@ -40,14 +39,13 @@ namespace MediaBrowser.Api
internal IHttpResultFactory ResultFactory { get; private set; }
/// <summary>
/// The application paths
/// Gets the configuration manager.
/// </summary>
private readonly IServerConfigurationManager _config;
internal IServerConfigurationManager ConfigurationManager { get; }
private readonly ISessionManager _sessionManager;
private readonly IFileSystem _fileSystem;
private readonly IMediaSourceManager _mediaSourceManager;
public readonly IProcessFactory ProcessFactory;
/// <summary>
/// The active transcoding jobs
@@ -73,15 +71,13 @@ namespace MediaBrowser.Api
IServerConfigurationManager config,
IFileSystem fileSystem,
IMediaSourceManager mediaSourceManager,
IProcessFactory processFactory,
IHttpResultFactory resultFactory)
{
Logger = logger;
_sessionManager = sessionManager;
_config = config;
ConfigurationManager = config;
_fileSystem = fileSystem;
_mediaSourceManager = mediaSourceManager;
ProcessFactory = processFactory;
ResultFactory = resultFactory;
_sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress;
@@ -160,17 +156,12 @@ namespace MediaBrowser.Api
return Task.CompletedTask;
}
public EncodingOptions GetEncodingOptions()
{
return ConfigurationManagerExtensions.GetConfiguration<EncodingOptions>(_config, "encoding");
}
/// <summary>
/// Deletes the encoded media cache.
/// </summary>
private void DeleteEncodedMediaCache()
{
var path = _config.ApplicationPaths.GetTranscodingTempPath();
var path = ConfigurationManager.GetTranscodePath();
if (!Directory.Exists(path))
{

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -298,11 +297,26 @@ namespace MediaBrowser.Api
var pathInfo = Parse(Request.PathInfo);
var first = pathInfo[0];
string baseUrl = ApiEntryPoint.Instance.ConfigurationManager.Configuration.BaseUrl;
// backwards compatibility
if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase) ||
string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase))
if (baseUrl.Length == 0)
{
if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase)
|| string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase))
{
index++;
}
}
else if (string.Equals(first, baseUrl.Remove(0, 1)))
{
index++;
var second = pathInfo[1];
if (string.Equals(second, "mediabrowser", StringComparison.OrdinalIgnoreCase)
|| string.Equals(second, "emby", StringComparison.OrdinalIgnoreCase))
{
index++;
}
}
return pathInfo[index];

View File

@@ -52,6 +52,7 @@ namespace MediaBrowser.Api
public bool? IsFile { get; set; }
}
[Obsolete]
[Route("/Environment/NetworkShares", "GET", Summary = "Gets shares from a network device")]
public class GetNetworkShares : IReturn<List<FileSystemEntryInfo>>
{
@@ -192,22 +193,18 @@ namespace MediaBrowser.Api
var networkPrefix = UncSeparatorString + UncSeparatorString;
if (path.StartsWith(networkPrefix, StringComparison.OrdinalIgnoreCase) && path.LastIndexOf(UncSeparator) == 1)
if (path.StartsWith(networkPrefix, StringComparison.OrdinalIgnoreCase)
&& path.LastIndexOf(UncSeparator) == 1)
{
return ToOptimizedResult(GetNetworkShares(path).OrderBy(i => i.Path).ToList());
return ToOptimizedResult(Array.Empty<FileSystemEntryInfo>());
}
return ToOptimizedResult(GetFileSystemEntries(request).ToList());
}
[Obsolete]
public object Get(GetNetworkShares request)
{
var path = request.Path;
var shares = GetNetworkShares(path).OrderBy(i => i.Path).ToList();
return ToOptimizedResult(shares);
}
=> ToOptimizedResult(Array.Empty<FileSystemEntryInfo>());
/// <summary>
/// Gets the specified request.
@@ -241,26 +238,7 @@ namespace MediaBrowser.Api
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Get(GetNetworkDevices request)
{
var result = _networkManager.GetNetworkDevices().ToList();
return ToOptimizedResult(result);
}
/// <summary>
/// Gets the network shares.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>IEnumerable{FileSystemEntryInfo}.</returns>
private IEnumerable<FileSystemEntryInfo> GetNetworkShares(string path)
{
return _networkManager.GetNetworkShares(path).Where(s => s.ShareType == NetworkShareType.Disk).Select(c => new FileSystemEntryInfo
{
Name = c.Name,
Path = Path.Combine(path, c.Name),
Type = FileSystemEntryType.NetworkShare
});
}
=> ToOptimizedResult(Array.Empty<FileSystemEntryInfo>());
/// <summary>
/// Gets the file system entries.

View File

@@ -32,7 +32,7 @@ namespace MediaBrowser.Api
if (string.IsNullOrEmpty(val))
{
return new ItemFields[] { };
return Array.Empty<ItemFields>();
}
return val.Split(',').Select(v =>
@@ -41,6 +41,7 @@ namespace MediaBrowser.Api
{
return (ItemFields?)value;
}
return null;
}).Where(i => i.HasValue).Select(i => i.Value).ToArray();

View File

@@ -227,15 +227,17 @@ namespace MediaBrowser.Api
//item.ProductionYear = request.ProductionYear;
//item.Name = request.Name;
return _providerManager.RefreshFullItem(item, new MetadataRefreshOptions(new DirectoryService(Logger, _fileSystem))
{
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
ReplaceAllMetadata = true,
ReplaceAllImages = request.ReplaceAllImages,
SearchResult = request
}, CancellationToken.None);
return _providerManager.RefreshFullItem(
item,
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
{
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
ReplaceAllMetadata = true,
ReplaceAllImages = request.ReplaceAllImages,
SearchResult = request
},
CancellationToken.None);
}
/// <summary>
@@ -294,11 +296,9 @@ namespace MediaBrowser.Api
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
using (var stream = result.Content)
using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
{
using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
{
await stream.CopyToAsync(filestream).ConfigureAwait(false);
}
await stream.CopyToAsync(filestream).ConfigureAwait(false);
}
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
@@ -311,9 +311,6 @@ namespace MediaBrowser.Api
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
private string GetFullCachePath(string filename)
{
return Path.Combine(_appPaths.CachePath, "remote-images", filename.Substring(0, 1), filename);
}
=> Path.Combine(_appPaths.CachePath, "remote-images", filename.Substring(0, 1), filename);
}
}

View File

@@ -63,7 +63,7 @@ namespace MediaBrowser.Api
private MetadataRefreshOptions GetRefreshOptions(RefreshItem request)
{
return new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
return new MetadataRefreshOptions(new DirectoryService(_fileSystem))
{
MetadataRefreshMode = request.MetadataRefreshMode,
ImageRefreshMode = request.ImageRefreshMode,

View File

@@ -225,13 +225,15 @@ namespace MediaBrowser.Api
if (displayOrderChanged)
{
_providerManager.QueueRefresh(series.Id, new MetadataRefreshOptions(new DirectoryService(Logger, _fileSystem))
{
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
ReplaceAllMetadata = true
}, RefreshPriority.High);
_providerManager.QueueRefresh(
series.Id,
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
{
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
ReplaceAllMetadata = true
},
RefreshPriority.High);
}
}

View File

@@ -8,6 +8,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Api.UserLibrary;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
@@ -25,7 +26,6 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Services;
using Microsoft.Net.Http.Headers;
using static MediaBrowser.Common.HexHelper;
namespace MediaBrowser.Api.LiveTv
{
@@ -887,8 +887,9 @@ namespace MediaBrowser.Api.LiveTv
{
// SchedulesDirect requires a SHA1 hash of the user's password
// https://github.com/SchedulesDirect/JSON-Service/wiki/API-20141201#obtain-a-token
using (SHA1 sha = SHA1.Create()) {
return ToHexString(
using (SHA1 sha = SHA1.Create())
{
return Hex.Encode(
sha.ComputeHash(Encoding.UTF8.GetBytes(str)));
}
}

View File

@@ -10,7 +10,7 @@
</ItemGroup>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

View File

@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Services;
@@ -126,12 +126,6 @@ namespace MediaBrowser.Api
_appHost = appHost;
}
/// <summary>
/// Gets the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
///
/// <summary>
/// Gets the specified request.
/// </summary>
@@ -139,7 +133,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetPackage request)
{
var packages = _installationManager.GetAvailablePackages(CancellationToken.None, applicationVersion: typeof(PackageService).Assembly.GetName().Version).Result;
var packages = _installationManager.GetAvailablePackages().Result;
var result = packages.FirstOrDefault(p => string.Equals(p.guid, request.AssemblyGuid ?? "none", StringComparison.OrdinalIgnoreCase))
?? packages.FirstOrDefault(p => p.name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
@@ -154,7 +148,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public async Task<object> Get(GetPackages request)
{
IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages(CancellationToken.None, false, request.PackageType, typeof(PackageService).Assembly.GetName().Version).ConfigureAwait(false);
IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
if (!string.IsNullOrEmpty(request.TargetSystems))
{
@@ -163,11 +157,6 @@ namespace MediaBrowser.Api
packages = packages.Where(p => apps.Contains(p.targetSystem));
}
if (request.IsPremium.HasValue)
{
packages = packages.Where(p => p.isPremium == request.IsPremium.Value);
}
if (request.IsAdult.HasValue)
{
packages = packages.Where(p => p.adult == request.IsAdult.Value);
@@ -188,13 +177,21 @@ namespace MediaBrowser.Api
/// <exception cref="ResourceNotFoundException"></exception>
public async Task Post(InstallPackage request)
{
var package = string.IsNullOrEmpty(request.Version) ?
await _installationManager.GetLatestCompatibleVersion(request.Name, request.AssemblyGuid, typeof(PackageService).Assembly.GetName().Version, request.UpdateClass).ConfigureAwait(false) :
await _installationManager.GetPackage(request.Name, request.AssemblyGuid, request.UpdateClass, Version.Parse(request.Version)).ConfigureAwait(false);
var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
var package = _installationManager.GetCompatibleVersions(
packages,
request.Name,
new Guid(request.AssemblyGuid),
string.IsNullOrEmpty(request.Version) ? null : Version.Parse(request.Version),
request.UpdateClass).FirstOrDefault();
if (package == null)
{
throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name));
throw new ResourceNotFoundException(
string.Format(
CultureInfo.InvariantCulture,
"Package not found: {0}",
request.Name));
}
await _installationManager.InstallPackage(package);

View File

@@ -7,6 +7,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
@@ -141,7 +142,7 @@ namespace MediaBrowser.Api.Playback
var filename = data.GetMD5().ToString("N", CultureInfo.InvariantCulture);
var ext = outputFileExtension.ToLowerInvariant();
var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath;
var folder = ServerConfigurationManager.GetTranscodePath();
if (EnableOutputInSubFolder)
{
@@ -215,7 +216,7 @@ namespace MediaBrowser.Api.Playback
}
}
var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
var encodingOptions = ServerConfigurationManager.GetEncodingOptions();
var process = new Process()
{
@@ -289,17 +290,22 @@ namespace MediaBrowser.Api.Playback
throw;
}
Logger.LogDebug("Launched ffmpeg process");
state.TranscodingJob = transcodingJob;
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
_ = new JobLogger(Logger).StartStreamingLog(state, process.StandardError.BaseStream, logStream);
// Wait for the file to exist before proceeeding
while (!File.Exists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
var ffmpegTargetFile = state.WaitForPath ?? outputPath;
Logger.LogDebug("Waiting for the creation of {0}", ffmpegTargetFile);
while (!File.Exists(ffmpegTargetFile) && !transcodingJob.HasExited)
{
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
}
Logger.LogDebug("File {0} created or transcoding has finished", ffmpegTargetFile);
if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited)
{
await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
@@ -314,6 +320,7 @@ namespace MediaBrowser.Api.Playback
{
StartThrottler(state, transcodingJob);
}
Logger.LogDebug("StartFfMpeg() finished successfully");
return transcodingJob;
}
@@ -582,7 +589,7 @@ namespace MediaBrowser.Api.Playback
/// <summary>
/// Parses query parameters as StreamOptions
/// <summary>
/// </summary>
/// <param name="request">The stream request.</param>
private void ParseStreamOptions(StreamRequest request)
{
@@ -839,7 +846,7 @@ namespace MediaBrowser.Api.Playback
? GetOutputFileExtension(state)
: ('.' + state.OutputContainer);
var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
var encodingOptions = ServerConfigurationManager.GetEncodingOptions();
state.OutputFilePath = GetOutputFilePath(state, encodingOptions, ext);

View File

@@ -192,6 +192,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (File.Exists(segmentPath))
{
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
Logger.LogDebug("returning {0} [it exists, try 1]", segmentPath);
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
}
@@ -207,6 +208,7 @@ namespace MediaBrowser.Api.Playback.Hls
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
transcodingLock.Release();
released = true;
Logger.LogDebug("returning {0} [it exists, try 2]", segmentPath);
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
}
else
@@ -243,6 +245,7 @@ namespace MediaBrowser.Api.Playback.Hls
request.StartTimeTicks = GetStartPositionTicks(state, requestedIndex);
state.WaitForPath = segmentPath;
job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
}
catch
@@ -277,7 +280,7 @@ namespace MediaBrowser.Api.Playback.Hls
// await Task.Delay(50, cancellationToken).ConfigureAwait(false);
//}
Logger.LogInformation("returning {0}", segmentPath);
Logger.LogDebug("returning {0} [general case]", segmentPath);
job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
}
@@ -458,56 +461,68 @@ namespace MediaBrowser.Api.Playback.Hls
TranscodingJob transcodingJob,
CancellationToken cancellationToken)
{
var segmentFileExists = File.Exists(segmentPath);
// If all transcoding has completed, just return immediately
if (transcodingJob != null && transcodingJob.HasExited && segmentFileExists)
var segmentExists = File.Exists(segmentPath);
if (segmentExists)
{
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
}
if (transcodingJob != null && transcodingJob.HasExited)
{
// Transcoding job is over, so assume all existing files are ready
Logger.LogDebug("serving up {0} as transcode is over", segmentPath);
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
}
if (segmentFileExists)
{
var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
// If requested segment is less than transcoding position, we can't transcode backwards, so assume it's ready
if (segmentIndex < currentTranscodingIndex)
{
Logger.LogDebug("serving up {0} as transcode index {1} is past requested point {2}", segmentPath, currentTranscodingIndex, segmentIndex);
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
}
}
var segmentFilename = Path.GetFileName(segmentPath);
while (!cancellationToken.IsCancellationRequested)
var nextSegmentPath = GetSegmentPath(state, playlistPath, segmentIndex + 1);
if (transcodingJob != null)
{
try
while (!cancellationToken.IsCancellationRequested && !transcodingJob.HasExited)
{
var text = File.ReadAllText(playlistPath, Encoding.UTF8);
// If it appears in the playlist, it's done
if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
// To be considered ready, the segment file has to exist AND
// either the transcoding job should be done or next segment should also exist
if (segmentExists)
{
if (!segmentFileExists)
{
segmentFileExists = File.Exists(segmentPath);
}
if (segmentFileExists)
if (transcodingJob.HasExited || File.Exists(nextSegmentPath))
{
Logger.LogDebug("serving up {0} as it deemed ready", segmentPath);
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
}
//break;
}
}
catch (IOException)
{
// May get an error if the file is locked
else
{
segmentExists = File.Exists(segmentPath);
if (segmentExists)
{
continue; // avoid unnecessary waiting if segment just became available
}
}
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
if (!File.Exists(segmentPath))
{
Logger.LogWarning("cannot serve {0} as transcoding quit before we got there", segmentPath);
}
else
{
Logger.LogDebug("serving {0} as it's on disk and transcoding stopped", segmentPath);
}
cancellationToken.ThrowIfCancellationRequested();
}
else
{
Logger.LogWarning("cannot serve {0} as it doesn't exist and no transcode is running", segmentPath);
}
cancellationToken.ThrowIfCancellationRequested();
return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
}
@@ -521,6 +536,7 @@ namespace MediaBrowser.Api.Playback.Hls
FileShare = FileShareMode.ReadWrite,
OnComplete = () =>
{
Logger.LogDebug("finished serving {0}", segmentPath);
if (transcodingJob != null)
{
transcodingJob.DownloadPositionTicks = Math.Max(transcodingJob.DownloadPositionTicks ?? segmentEndingPositionTicks, segmentEndingPositionTicks);
@@ -909,9 +925,23 @@ namespace MediaBrowser.Api.Playback.Hls
else
{
var keyFrameArg = string.Format(
CultureInfo.InvariantCulture,
" -force_key_frames:0 \"expr:gte(t,{0}+n_forced*{1})\"",
GetStartNumber(state) * state.SegmentLength,
state.SegmentLength.ToString(CultureInfo.InvariantCulture));
state.SegmentLength);
if (state.TargetFramerate.HasValue)
{
// This is to make sure keyframe interval is limited to our segment,
// as forcing keyframes is not enough.
// Example: we encoded half of desired length, then codec detected
// scene cut and inserted a keyframe; next forced keyframe would
// be created outside of segment, which breaks seeking.
keyFrameArg += string.Format(
CultureInfo.InvariantCulture,
" -g {0} -keyint_min {0}",
(int)(state.SegmentLength * state.TargetFramerate)
);
}
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
@@ -955,6 +985,15 @@ namespace MediaBrowser.Api.Playback.Hls
var threads = EncodingHelper.GetNumberOfThreads(state, encodingOptions, videoCodec);
if (state.BaseRequest.BreakOnNonKeyFrames)
{
// FIXME: this is actually a workaround, as ideally it really should be the client which decides whether non-keyframe
// breakpoints are supported; but current implementation always uses "ffmpeg input seeking" which is liable
// to produce a missing part of video stream before first keyframe is encountered, which may lead to
// awkward cases like a few starting HLS segments having no video whatsoever, which breaks hls.js
Logger.LogInformation("Current HLS implementation doesn't support non-keyframe breaks but one is requested, ignoring that request");
state.BaseRequest.BreakOnNonKeyFrames = false;
}
var inputModifier = EncodingHelper.GetInputModifier(state, encodingOptions);
// If isEncoding is true we're actually starting ffmpeg
@@ -965,14 +1004,6 @@ namespace MediaBrowser.Api.Playback.Hls
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request);
var timeDeltaParam = string.Empty;
if (isEncoding && state.TargetFramerate > 0)
{
float startTime = 1 / (state.TargetFramerate.Value * 2);
timeDeltaParam = string.Format(CultureInfo.InvariantCulture, "-segment_time_delta {0:F3}", startTime);
}
var segmentFormat = GetSegmentFileExtension(state.Request).TrimStart('.');
if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
{
@@ -980,7 +1011,7 @@ namespace MediaBrowser.Api.Playback.Hls
}
return string.Format(
"{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format {11} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
"{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f hls -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {6} -individual_header_trailer 0 -hls_segment_type {7} -start_number {8} -hls_segment_filename \"{9}\" -hls_playlist_type vod -hls_list_size 0 -y \"{10}\"",
inputModifier,
EncodingHelper.GetInputArgument(state, encodingOptions),
threads,
@@ -988,11 +1019,10 @@ namespace MediaBrowser.Api.Playback.Hls
GetVideoArguments(state, encodingOptions),
GetAudioArguments(state, encodingOptions),
state.SegmentLength.ToString(CultureInfo.InvariantCulture),
segmentFormat,
startNumberParam,
outputPath,
outputTsArg,
timeDeltaParam,
segmentFormat
outputPath
).Trim();
}
}

View File

@@ -2,7 +2,7 @@ using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
@@ -83,13 +83,11 @@ namespace MediaBrowser.Api.Playback.Hls
public class HlsSegmentService : BaseApiService
{
private readonly IServerApplicationPaths _appPaths;
private readonly IServerConfigurationManager _config;
private readonly IFileSystem _fileSystem;
public HlsSegmentService(IServerApplicationPaths appPaths, IServerConfigurationManager config, IFileSystem fileSystem)
public HlsSegmentService(IServerConfigurationManager config, IFileSystem fileSystem)
{
_appPaths = appPaths;
_config = config;
_fileSystem = fileSystem;
}
@@ -97,7 +95,7 @@ namespace MediaBrowser.Api.Playback.Hls
public Task<object> Get(GetHlsPlaylistLegacy request)
{
var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_appPaths.TranscodingTempPath, file);
file = Path.Combine(_config.GetTranscodePath(), file);
return GetFileResult(file, file);
}
@@ -115,8 +113,7 @@ namespace MediaBrowser.Api.Playback.Hls
public Task<object> Get(GetHlsVideoSegmentLegacy request)
{
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
var transcodeFolderPath = _config.ApplicationPaths.TranscodingTempPath;
var transcodeFolderPath = _config.GetTranscodePath();
file = Path.Combine(transcodeFolderPath, file);
var normalizedPlaylistId = request.PlaylistId;
@@ -136,7 +133,7 @@ namespace MediaBrowser.Api.Playback.Hls
{
// TODO: Deprecate with new iOS app
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_appPaths.TranscodingTempPath, file);
file = Path.Combine(_config.GetTranscodePath(), file);
return ResultFactory.GetStaticFileResult(Request, file, FileShareMode.ReadWrite);
}

View File

@@ -321,7 +321,7 @@ namespace MediaBrowser.Api.Session
DateCreated = DateTime.UtcNow,
DeviceId = _appHost.SystemId,
DeviceName = _appHost.FriendlyName,
AppVersion = _appHost.ApplicationVersion
AppVersion = _appHost.ApplicationVersionString
});
}

View File

@@ -1,135 +0,0 @@
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Api
{
[Route("/Startup/Complete", "POST", Summary = "Reports that the startup wizard has been completed", IsHidden = true)]
public class ReportStartupWizardComplete : IReturnVoid
{
}
[Route("/Startup/Configuration", "GET", Summary = "Gets initial server configuration", IsHidden = true)]
public class GetStartupConfiguration : IReturn<StartupConfiguration>
{
}
[Route("/Startup/Configuration", "POST", Summary = "Updates initial server configuration", IsHidden = true)]
public class UpdateStartupConfiguration : StartupConfiguration, IReturnVoid
{
}
[Route("/Startup/RemoteAccess", "POST", Summary = "Updates initial server configuration", IsHidden = true)]
public class UpdateRemoteAccessConfiguration : IReturnVoid
{
public bool EnableRemoteAccess { get; set; }
public bool EnableAutomaticPortMapping { get; set; }
}
[Route("/Startup/User", "GET", Summary = "Gets initial user info", IsHidden = true)]
public class GetStartupUser : IReturn<StartupUser>
{
}
[Route("/Startup/User", "POST", Summary = "Updates initial user info", IsHidden = true)]
public class UpdateStartupUser : StartupUser
{
}
[Authenticated(AllowBeforeStartupWizard = true, Roles = "Admin")]
public class StartupWizardService : BaseApiService
{
private readonly IServerConfigurationManager _config;
private readonly IServerApplicationHost _appHost;
private readonly IUserManager _userManager;
private readonly IMediaEncoder _mediaEncoder;
private readonly IHttpClient _httpClient;
public StartupWizardService(IServerConfigurationManager config, IHttpClient httpClient, IServerApplicationHost appHost, IUserManager userManager, IMediaEncoder mediaEncoder)
{
_config = config;
_appHost = appHost;
_userManager = userManager;
_mediaEncoder = mediaEncoder;
_httpClient = httpClient;
}
public void Post(ReportStartupWizardComplete request)
{
_config.Configuration.IsStartupWizardCompleted = true;
_config.SetOptimalValues();
_config.SaveConfiguration();
}
public object Get(GetStartupConfiguration request)
{
var result = new StartupConfiguration
{
UICulture = _config.Configuration.UICulture,
MetadataCountryCode = _config.Configuration.MetadataCountryCode,
PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage
};
return result;
}
public void Post(UpdateStartupConfiguration request)
{
_config.Configuration.UICulture = request.UICulture;
_config.Configuration.MetadataCountryCode = request.MetadataCountryCode;
_config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
_config.SaveConfiguration();
}
public void Post(UpdateRemoteAccessConfiguration request)
{
_config.Configuration.EnableRemoteAccess = request.EnableRemoteAccess;
_config.Configuration.EnableUPnP = request.EnableAutomaticPortMapping;
_config.SaveConfiguration();
}
public object Get(GetStartupUser request)
{
var user = _userManager.Users.First();
return new StartupUser
{
Name = user.Name,
Password = user.Password
};
}
public async Task Post(UpdateStartupUser request)
{
var user = _userManager.Users.First();
user.Name = request.Name;
_userManager.UpdateUser(user);
if (!string.IsNullOrEmpty(request.Password))
{
await _userManager.ChangePassword(user, request.Password).ConfigureAwait(false);
}
}
}
public class StartupConfiguration
{
public string UICulture { get; set; }
public string MetadataCountryCode { get; set; }
public string PreferredMetadataLanguage { get; set; }
}
public class StartupUser
{
public string Name { get; set; }
public string Password { get; set; }
}
}

View File

@@ -279,13 +279,12 @@ namespace MediaBrowser.Api.Subtitles
await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None)
.ConfigureAwait(false);
_providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(Logger, _fileSystem)), RefreshPriority.High);
_providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High);
}
catch (Exception ex)
{
Logger.LogError(ex, "Error downloading subtitles");
}
});
}
}

View File

@@ -109,6 +109,11 @@ namespace MediaBrowser.Api.UserLibrary
NameContains = query.NameContains ?? query.SearchTerm
});
if ((query.IsFavorite ?? false) && query.User != null)
{
items = items.Where(i => UserDataRepository.GetUserData(query.User, i).IsFavorite).ToList();
}
return new QueryResult<(BaseItem, ItemCounts)>
{
TotalRecordCount = items.Count,

View File

@@ -413,7 +413,7 @@ namespace MediaBrowser.Api.UserLibrary
if (!hasMetdata)
{
var options = new MetadataRefreshOptions(new DirectoryService(Logger, _fileSystem))
var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem))
{
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
ImageRefreshMode = MetadataRefreshMode.FullRefresh,

View File

@@ -10,6 +10,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Api.UserLibrary
{
@@ -49,7 +50,12 @@ namespace MediaBrowser.Api.UserLibrary
private readonly IAuthorizationContext _authContext;
private readonly ILibraryManager _libraryManager;
public UserViewsService(IUserManager userManager, IUserViewManager userViewManager, IDtoService dtoService, IAuthorizationContext authContext, ILibraryManager libraryManager)
public UserViewsService(
IUserManager userManager,
IUserViewManager userViewManager,
IDtoService dtoService,
IAuthorizationContext authContext,
ILibraryManager libraryManager)
{
_userManager = userManager;
_userViewManager = userViewManager;