add migrations for new release

pull/702/head
Luke Pulverenti 9 years ago
parent f5f5285306
commit a0b1ddf0a7

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

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

@ -487,6 +487,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{ {
_logger.Info("Streaming Channel " + channelId); _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) foreach (var hostInstance in _liveTvManager.TunerHosts)
{ {
try try
@ -653,40 +676,56 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try try
{ {
var mediaStreamInfo = await GetChannelStream(timer.ChannelId, null, CancellationToken.None); var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None);
var mediaStreamInfo = result.Item1;
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg var isResourceOpen = true;
await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
var duration = recordingEndDate - DateTime.UtcNow; // Unfortunately due to the semaphore we have to have a nested try/finally
try
HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
{ {
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);
var duration = recordingEndDate - DateTime.UtcNow;
recording.Path = recordPath; HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
recording.Status = RecordingStatus.InProgress; {
recording.DateLastUpdated = DateTime.UtcNow; Url = mediaStreamInfo.Path
_recordingProvider.Update(recording); };
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;
_logger.Info("Beginning recording."); await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
}
}
httpRequestOptions.BufferContent = false; recording.Status = RecordingStatus.Completed;
var durationToken = new CancellationTokenSource(duration); _logger.Info("Recording completed");
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; }
httpRequestOptions.CancellationToken = linkedToken; finally
_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)) if (isResourceOpen)
{ {
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken); result.Item2.Release();
} }
} }
recording.Status = RecordingStatus.Completed;
_logger.Info("Recording completed");
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {

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

@ -141,7 +141,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
protected abstract Task<MediaSourceInfo> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken); 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)) if (IsValidChannelId(channelId))
{ {
@ -173,9 +173,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
try try
{ {
var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false); var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
var resourcePool = GetLock(host.Url);
await AddMediaInfo(stream, false, cancellationToken).ConfigureAwait(false);
return stream; await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false);
return new Tuple<MediaSourceInfo, SemaphoreSlim>(stream, resourcePool);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -187,7 +188,40 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
throw new LiveTvConflictException(); 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; var originalRuntime = mediaSource.RunTimeTicks;

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

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

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

@ -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();
}
}
}
Loading…
Cancel
Save