commit
9d62e402dd
|
@ -154,7 +154,7 @@ namespace MediaBrowser.Controller.Persistence
|
|||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>List<BaseItem>.</returns>
|
||||
IEnumerable<BaseItem> GetItemList(InternalItemsQuery query);
|
||||
List<BaseItem> GetItemList(InternalItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the inherited values.
|
||||
|
|
|
@ -189,6 +189,15 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
SubtitleProfiles = new[]
|
||||
{
|
||||
new SubtitleProfile
|
||||
{
|
||||
Format = "srt",
|
||||
Method = SubtitleDeliveryMethod.External
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,5 +77,7 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles />
|
||||
<SubtitleProfiles />
|
||||
<SubtitleProfiles>
|
||||
<SubtitleProfile format="srt" method="External" />
|
||||
</SubtitleProfiles>
|
||||
</Profile>
|
|
@ -94,7 +94,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
// Add resolution params, if specified
|
||||
if (!hasGraphicalSubs)
|
||||
{
|
||||
args += GetOutputSizeParam(state, videoCodec);
|
||||
args += await GetOutputSizeParam(state, videoCodec).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var qualityParam = GetVideoQualityParam(state, videoCodec);
|
||||
|
|
|
@ -1306,7 +1306,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
ItemIds = new[] { item.Id.ToString("N") }
|
||||
});
|
||||
|
||||
dto.ArtistItems = artistItems.Items
|
||||
dto.AlbumArtists = artistItems.Items
|
||||
.Select(i =>
|
||||
{
|
||||
var artist = i.Item1;
|
||||
|
|
|
@ -1059,6 +1059,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
if (recordingStatus == RecordingStatus.Completed)
|
||||
{
|
||||
timer.Status = RecordingStatus.Completed;
|
||||
_timerProvider.AddOrUpdate(timer);
|
||||
|
||||
OnSuccessfulRecording(info.IsSeries, recordPath);
|
||||
_timerProvider.Delete(timer);
|
||||
}
|
||||
|
@ -1067,7 +1070,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
const int retryIntervalSeconds = 60;
|
||||
_logger.Info("Retrying recording in {0} seconds.", retryIntervalSeconds);
|
||||
|
||||
_timerProvider.StartTimer(timer, TimeSpan.FromSeconds(retryIntervalSeconds));
|
||||
timer.Status = RecordingStatus.New;
|
||||
timer.StartDate = DateTime.UtcNow.AddSeconds(retryIntervalSeconds);
|
||||
_timerProvider.AddOrUpdate(timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1119,7 +1124,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
if (regInfo.IsValid)
|
||||
{
|
||||
return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, config);
|
||||
return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, config, _httpClient);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -22,8 +24,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly IServerApplicationPaths _appPaths;
|
||||
private readonly LiveTvOptions _liveTvOptions;
|
||||
private bool _hasExited;
|
||||
private Stream _logFileStream;
|
||||
|
@ -32,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
private readonly IJsonSerializer _json;
|
||||
private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
|
||||
public EncodedRecorder(ILogger logger, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IApplicationPaths appPaths, IJsonSerializer json, LiveTvOptions liveTvOptions)
|
||||
public EncodedRecorder(ILogger logger, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IServerApplicationPaths appPaths, IJsonSerializer json, LiveTvOptions liveTvOptions, IHttpClient httpClient)
|
||||
{
|
||||
_logger = logger;
|
||||
_fileSystem = fileSystem;
|
||||
|
@ -40,6 +43,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
_appPaths = appPaths;
|
||||
_json = json;
|
||||
_liveTvOptions = liveTvOptions;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public string GetOutputPath(MediaSourceInfo mediaSource, string targetFile)
|
||||
|
@ -49,20 +53,73 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||
{
|
||||
if (mediaSource.RunTimeTicks.HasValue)
|
||||
var tempfile = Path.Combine(_appPaths.TranscodingTempPath, Guid.NewGuid().ToString("N") + ".ts");
|
||||
|
||||
try
|
||||
{
|
||||
// The media source already has a fixed duration
|
||||
// But add another stop 1 minute later just in case the recording gets stuck for any reason
|
||||
var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1)));
|
||||
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
||||
await RecordInternal(mediaSource, tempfile, targetFile, duration, onStarted, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
finally
|
||||
{
|
||||
// The media source if infinite so we need to handle stopping ourselves
|
||||
var durationToken = new CancellationTokenSource(duration);
|
||||
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
||||
File.Delete(tempfile);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RecordInternal(MediaSourceInfo mediaSource, string tempFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||
{
|
||||
var httpRequestOptions = new HttpRequestOptions()
|
||||
{
|
||||
Url = mediaSource.Path
|
||||
};
|
||||
|
||||
httpRequestOptions.BufferContent = false;
|
||||
|
||||
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false))
|
||||
{
|
||||
_logger.Info("Opened recording stream from tuner provider");
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
|
||||
|
||||
using (var output = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||
{
|
||||
//onStarted();
|
||||
|
||||
_logger.Info("Copying recording stream to file {0}", tempFile);
|
||||
|
||||
var bufferMs = 5000;
|
||||
|
||||
if (mediaSource.RunTimeTicks.HasValue)
|
||||
{
|
||||
// The media source already has a fixed duration
|
||||
// But add another stop 1 minute later just in case the recording gets stuck for any reason
|
||||
var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1)));
|
||||
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The media source if infinite so we need to handle stopping ourselves
|
||||
var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMilliseconds(bufferMs)));
|
||||
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
||||
}
|
||||
|
||||
var tempFileTask = response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, cancellationToken);
|
||||
|
||||
// Give the temp file a little time to build up
|
||||
await Task.Delay(bufferMs, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await RecordFromFile(mediaSource, tempFile, targetFile, onStarted, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await tempFileTask.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Info("Recording completed to file {0}", targetFile);
|
||||
}
|
||||
|
||||
private async Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, Action onStarted, CancellationToken cancellationToken)
|
||||
{
|
||||
_targetPath = targetFile;
|
||||
_fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile));
|
||||
|
||||
|
@ -79,7 +136,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
RedirectStandardInput = true,
|
||||
|
||||
FileName = _mediaEncoder.EncoderPath,
|
||||
Arguments = GetCommandLineArgs(mediaSource, targetFile, duration),
|
||||
Arguments = GetCommandLineArgs(mediaSource, inputFile, targetFile),
|
||||
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
ErrorDialog = false
|
||||
|
@ -119,7 +176,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
await _taskCompletionSource.Task.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private string GetCommandLineArgs(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration)
|
||||
private string GetCommandLineArgs(MediaSourceInfo mediaSource, string inputTempFile, string targetFile)
|
||||
{
|
||||
string videoArgs;
|
||||
if (EncodeVideo(mediaSource))
|
||||
|
@ -135,14 +192,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
videoArgs = "-codec:v:0 copy";
|
||||
}
|
||||
|
||||
var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -re -i \"{0}\" -t {4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
|
||||
var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -re -i \"{0}\" -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
|
||||
|
||||
if (mediaSource.ReadAtNativeFramerate)
|
||||
{
|
||||
commandLineArgs = "-re " + commandLineArgs;
|
||||
}
|
||||
|
||||
commandLineArgs = string.Format(commandLineArgs, mediaSource.Path, targetFile, videoArgs, GetAudioArgs(mediaSource), _mediaEncoder.GetTimeParameter(duration.Ticks));
|
||||
commandLineArgs = string.Format(commandLineArgs, inputTempFile, targetFile, videoArgs, GetAudioArgs(mediaSource));
|
||||
|
||||
return commandLineArgs;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Controller.Power;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||
{
|
||||
|
@ -85,6 +86,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
private void AddTimer(TimerInfo item)
|
||||
{
|
||||
if (item.Status == RecordingStatus.Completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var startDate = RecordingHelper.GetStartTime(item);
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
|
@ -117,15 +123,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
}
|
||||
}
|
||||
|
||||
public void StartTimer(TimerInfo item, TimeSpan length)
|
||||
public void StartTimer(TimerInfo item, TimeSpan dueTime)
|
||||
{
|
||||
StopTimer(item);
|
||||
|
||||
var timer = new Timer(TimerCallback, item.Id, length, TimeSpan.Zero);
|
||||
var timer = new Timer(TimerCallback, item.Id, dueTime, TimeSpan.Zero);
|
||||
|
||||
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));
|
||||
_logger.Info("Creating recording timer for {0}, {1}. Timer will fire in {2} minutes", item.Id, item.Name, dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1742,7 +1742,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
return " from TypedBaseItems A";
|
||||
}
|
||||
|
||||
public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
|
||||
public List<BaseItem> GetItemList(InternalItemsQuery query)
|
||||
{
|
||||
if (query == null)
|
||||
{
|
||||
|
@ -1842,6 +1842,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
CheckDisposed();
|
||||
|
||||
if (!query.EnableTotalRecordCount || (!query.Limit.HasValue && (query.StartIndex ?? 0) == 0))
|
||||
{
|
||||
var list = GetItemList(query);
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
Items = list.ToArray(),
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
|
@ -2196,6 +2206,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
CheckDisposed();
|
||||
|
||||
if (!query.EnableTotalRecordCount || (!query.Limit.HasValue && (query.StartIndex ?? 0) == 0))
|
||||
{
|
||||
var list = GetItemIdsList(query);
|
||||
return new QueryResult<Guid>
|
||||
{
|
||||
Items = list.ToArray(),
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
|
|
Loading…
Reference in New Issue
Block a user