add migrations for new release

This commit is contained in:
Luke Pulverenti 2015-10-16 14:11:11 -04:00
parent f5f5285306
commit a0b1ddf0a7
9 changed files with 171 additions and 43 deletions

View File

@ -1,4 +1,5 @@
using MediaBrowser.Model.Dto;
using System;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using System.Collections.Generic;
using System.Threading;
@ -37,7 +38,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="streamId">The stream identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
Task<Tuple<MediaSourceInfo,SemaphoreSlim>> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
/// <summary>
/// Gets the channel stream media sources.
/// </summary>

View File

@ -226,11 +226,15 @@ namespace MediaBrowser.Model.Configuration
public bool EnableDateLastRefresh { get; set; }
public string[] Migrations { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary>
public ServerConfiguration()
{
Migrations = new string[] {};
ImageSavingConvention = ImageSavingConvention.Compatible;
PublicPort = 8096;
PublicHttpsPort = 8920;

View File

@ -487,6 +487,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
_logger.Info("Streaming Channel " + channelId);
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
try
{
var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
result.Item2.Release();
return result.Item1;
}
catch (Exception e)
{
_logger.ErrorException("Error getting channel stream", e);
}
}
throw new ApplicationException("Tuner not found.");
}
private async Task<Tuple<MediaSourceInfo, SemaphoreSlim>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
{
_logger.Info("Streaming Channel " + channelId);
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
try
@ -653,40 +676,56 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try
{
var mediaStreamInfo = await GetChannelStream(timer.ChannelId, null, CancellationToken.None);
var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None);
var mediaStreamInfo = result.Item1;
var isResourceOpen = true;
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
var duration = recordingEndDate - DateTime.UtcNow;
HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
// Unfortunately due to the semaphore we have to have a nested try/finally
try
{
Url = mediaStreamInfo.Path
};
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
recording.Path = recordPath;
recording.Status = RecordingStatus.InProgress;
recording.DateLastUpdated = DateTime.UtcNow;
_recordingProvider.Update(recording);
var duration = recordingEndDate - DateTime.UtcNow;
_logger.Info("Beginning recording.");
httpRequestOptions.BufferContent = false;
var durationToken = new CancellationTokenSource(duration);
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
httpRequestOptions.CancellationToken = linkedToken;
_logger.Info("Writing file to path: " + recordPath);
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
{
using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
{
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
Url = mediaStreamInfo.Path
};
recording.Path = recordPath;
recording.Status = RecordingStatus.InProgress;
recording.DateLastUpdated = DateTime.UtcNow;
_recordingProvider.Update(recording);
_logger.Info("Beginning recording.");
httpRequestOptions.BufferContent = false;
var durationToken = new CancellationTokenSource(duration);
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
httpRequestOptions.CancellationToken = linkedToken;
_logger.Info("Writing file to path: " + recordPath);
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
{
using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
result.Item2.Release();
isResourceOpen = false;
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
}
}
recording.Status = RecordingStatus.Completed;
_logger.Info("Recording completed");
}
finally
{
if (isResourceOpen)
{
result.Item2.Release();
}
}
recording.Status = RecordingStatus.Completed;
_logger.Info("Recording completed");
}
catch (OperationCanceledException)
{

View File

@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.LiveTv
{
class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey
public class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey
{
private readonly ILiveTvManager _liveTvManager;
private readonly IConfigurationManager _config;

View File

@ -141,7 +141,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
protected abstract Task<MediaSourceInfo> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken);
public async Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
public async Task<Tuple<MediaSourceInfo, SemaphoreSlim>> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
{
if (IsValidChannelId(channelId))
{
@ -173,9 +173,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
try
{
var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
await AddMediaInfo(stream, false, cancellationToken).ConfigureAwait(false);
return stream;
var resourcePool = GetLock(host.Url);
await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false);
return new Tuple<MediaSourceInfo, SemaphoreSlim>(stream, resourcePool);
}
catch (Exception ex)
{
@ -187,7 +188,40 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
throw new LiveTvConflictException();
}
private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
/// <summary>
/// The _semaphoreLocks
/// </summary>
private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks = new ConcurrentDictionary<string, SemaphoreSlim>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Gets the lock.
/// </summary>
/// <param name="url">The filename.</param>
/// <returns>System.Object.</returns>
private SemaphoreSlim GetLock(string url)
{
return _semaphoreLocks.GetOrAdd(url, key => new SemaphoreSlim(1, 1));
}
private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
{
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
await AddMediaInfoInternal(mediaSource, isAudio, cancellationToken).ConfigureAwait(false);
// Leave the resource locked. it will be released upstream
}
catch (Exception)
{
// Release the resource if there's some kind of failure.
resourcePool.Release();
throw;
}
}
private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
{
var originalRuntime = mediaSource.RunTimeTicks;

View File

@ -1,5 +1,4 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Progress;
using MediaBrowser.Common.Progress;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@ -17,7 +16,7 @@ using MediaBrowser.Controller.Entities.Audio;
namespace MediaBrowser.Server.Implementations.Persistence
{
class CleanDatabaseScheduledTask : IScheduledTask
public class CleanDatabaseScheduledTask : IScheduledTask
{
private readonly ILibraryManager _libraryManager;
private readonly IItemRepository _itemRepo;

View File

@ -333,18 +333,18 @@ namespace MediaBrowser.Server.Startup.Common
});
LogManager.RemoveConsoleOutput();
PerformPostInitMigrations();
}
public override async Task Init(IProgress<double> progress)
public override Task Init(IProgress<double> progress)
{
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
PerformPreInitMigrations();
await base.Init(progress).ConfigureAwait(false);
PerformPostInitMigrations();
return base.Init(progress);
}
private void PerformPreInitMigrations()
@ -362,7 +362,10 @@ namespace MediaBrowser.Server.Startup.Common
private void PerformPostInitMigrations()
{
var migrations = new List<IVersionMigration>();
var migrations = new List<IVersionMigration>
{
new Release5767(ServerConfigurationManager, TaskManager)
};
foreach (var task in migrations)
{

View File

@ -72,6 +72,7 @@
<Compile Include="INativeApp.cs" />
<Compile Include="MbLinkShortcutHandler.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />
<Compile Include="Migrations\Release5767.cs" />
<Compile Include="Migrations\RenameXmlOptions.cs" />
<Compile Include="NativeEnvironment.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -0,0 +1,47 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Server.Implementations.LiveTv;
using MediaBrowser.Server.Implementations.Persistence;
using MediaBrowser.Server.Implementations.ScheduledTasks;
namespace MediaBrowser.Server.Startup.Common.Migrations
{
public class Release5767 : IVersionMigration
{
private readonly IServerConfigurationManager _config;
private readonly ITaskManager _taskManager;
public Release5767(IServerConfigurationManager config, ITaskManager taskManager)
{
_config = config;
_taskManager = taskManager;
}
public void Run()
{
var name = "5767";
if (_config.Configuration.Migrations.Contains(name, StringComparer.OrdinalIgnoreCase))
{
return;
}
Task.Run(async () =>
{
await Task.Delay(3000).ConfigureAwait(false);
_taskManager.QueueScheduledTask<RefreshChannelsScheduledTask>();
_taskManager.QueueScheduledTask<CleanDatabaseScheduledTask>();
_taskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
});
var list = _config.Configuration.Migrations.ToList();
list.Add(name);
_config.Configuration.Migrations = list.ToArray();
_config.SaveConfiguration();
}
}
}