update automated checkins

This commit is contained in:
Luke Pulverenti 2017-04-17 15:01:16 -04:00
parent 0b5019ed1b
commit 561028c907
12 changed files with 28 additions and 212 deletions

View File

@ -9,13 +9,10 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Threading; using MediaBrowser.Model.Threading;
@ -365,12 +362,10 @@ namespace Emby.Server.Implementations.Library
private readonly Dictionary<string, LiveStreamInfo> _openStreams = new Dictionary<string, LiveStreamInfo>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, LiveStreamInfo> _openStreams = new Dictionary<string, LiveStreamInfo>(StringComparer.OrdinalIgnoreCase);
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken) public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken)
{ {
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
enableAutoClose = false;
try try
{ {
var tuple = GetProvider(request.OpenToken); var tuple = GetProvider(request.OpenToken);
@ -389,8 +384,6 @@ namespace Emby.Server.Implementations.Library
var info = new LiveStreamInfo var info = new LiveStreamInfo
{ {
Date = DateTime.UtcNow,
EnableCloseTimer = enableAutoClose,
Id = mediaSource.LiveStreamId, Id = mediaSource.LiveStreamId,
MediaSource = mediaSource, MediaSource = mediaSource,
DirectStreamProvider = mediaSourceTuple.Item2 DirectStreamProvider = mediaSourceTuple.Item2
@ -398,11 +391,6 @@ namespace Emby.Server.Implementations.Library
_openStreams[mediaSource.LiveStreamId] = info; _openStreams[mediaSource.LiveStreamId] = info;
if (enableAutoClose)
{
StartCloseTimer();
}
var json = _jsonSerializer.SerializeToString(mediaSource); var json = _jsonSerializer.SerializeToString(mediaSource);
_logger.Debug("Live stream opened: " + json); _logger.Debug("Live stream opened: " + json);
var clone = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json); var clone = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
@ -462,28 +450,6 @@ namespace Emby.Server.Implementations.Library
return result.Item1; return result.Item1;
} }
public async Task PingLiveStream(string id, CancellationToken cancellationToken)
{
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
LiveStreamInfo info;
if (_openStreams.TryGetValue(id, out info))
{
info.Date = DateTime.UtcNow;
}
else
{
_logger.Error("Failed to ping live stream {0}", id);
}
}
finally
{
_liveStreamSemaphore.Release();
}
}
private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId) private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId)
{ {
_logger.Info("Closing live stream {0} with provider {1}", streamId, provider.GetType().Name); _logger.Info("Closing live stream {0} with provider {1}", streamId, provider.GetType().Name);
@ -525,11 +491,6 @@ namespace Emby.Server.Implementations.Library
await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2).ConfigureAwait(false); await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2).ConfigureAwait(false);
} }
if (_openStreams.Count == 0)
{
StopCloseTimer();
}
} }
} }
finally finally
@ -558,66 +519,11 @@ namespace Emby.Server.Implementations.Library
return new Tuple<IMediaSourceProvider, string>(provider, keyId); return new Tuple<IMediaSourceProvider, string>(provider, keyId);
} }
private ITimer _closeTimer;
private readonly TimeSpan _openStreamMaxAge = TimeSpan.FromSeconds(180);
private void StartCloseTimer()
{
StopCloseTimer();
_closeTimer = _timerFactory.Create(CloseTimerCallback, null, _openStreamMaxAge, _openStreamMaxAge);
}
private void StopCloseTimer()
{
var timer = _closeTimer;
if (timer != null)
{
_closeTimer = null;
timer.Dispose();
}
}
private async void CloseTimerCallback(object state)
{
List<LiveStreamInfo> infos;
await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
try
{
infos = _openStreams
.Values
.Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge)
.ToList();
}
finally
{
_liveStreamSemaphore.Release();
}
foreach (var info in infos)
{
if (!info.Closed)
{
try
{
await CloseLiveStream(info.Id).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.ErrorException("Error closing media source", ex);
}
}
}
}
/// <summary> /// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
StopCloseTimer();
Dispose(true); Dispose(true);
} }
@ -644,8 +550,6 @@ namespace Emby.Server.Implementations.Library
private class LiveStreamInfo private class LiveStreamInfo
{ {
public DateTime Date;
public bool EnableCloseTimer;
public string Id; public string Id;
public bool Closed; public bool Closed;
public MediaSourceInfo MediaSource; public MediaSourceInfo MediaSource;

View File

@ -190,7 +190,7 @@ namespace Emby.Server.Implementations.LiveTv
else if (width >= 1260) else if (width >= 1260)
{ {
videoStream.BitRate = 3000000; videoStream.BitRate = 4000000;
} }
else if (width >= 700) else if (width >= 700)

View File

@ -310,10 +310,7 @@ namespace Emby.Server.Implementations.Session
/// <summary> /// <summary>
/// Updates the now playing item id. /// Updates the now playing item id.
/// </summary> /// </summary>
/// <param name="session">The session.</param> private async Task UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem, bool updateLastCheckInTime)
/// <param name="info">The information.</param>
/// <param name="libraryItem">The library item.</param>
private async Task UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem)
{ {
if (string.IsNullOrWhiteSpace(info.MediaSourceId)) if (string.IsNullOrWhiteSpace(info.MediaSourceId))
{ {
@ -352,7 +349,11 @@ namespace Emby.Server.Implementations.Session
session.NowPlayingItem = info.Item; session.NowPlayingItem = info.Item;
session.LastActivityDate = DateTime.UtcNow; session.LastActivityDate = DateTime.UtcNow;
if (updateLastCheckInTime)
{
session.LastPlaybackCheckIn = DateTime.UtcNow; session.LastPlaybackCheckIn = DateTime.UtcNow;
}
session.PlayState.IsPaused = info.IsPaused; session.PlayState.IsPaused = info.IsPaused;
session.PlayState.PositionTicks = info.PositionTicks; session.PlayState.PositionTicks = info.PositionTicks;
@ -604,7 +605,7 @@ namespace Emby.Server.Implementations.Session
? null ? null
: GetNowPlayingItem(session, info.ItemId); : GetNowPlayingItem(session, info.ItemId);
await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false); await UpdateNowPlayingItem(session, info, libraryItem, true).ConfigureAwait(false);
if (!string.IsNullOrEmpty(session.DeviceId) && info.PlayMethod != PlayMethod.Transcode) if (!string.IsNullOrEmpty(session.DeviceId) && info.PlayMethod != PlayMethod.Transcode)
{ {
@ -671,14 +672,15 @@ namespace Emby.Server.Implementations.Session
await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false); await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false);
} }
public Task OnPlaybackProgress(PlaybackProgressInfo info)
{
return OnPlaybackProgress(info, false);
}
/// <summary> /// <summary>
/// Used to report playback progress for an item /// Used to report playback progress for an item
/// </summary> /// </summary>
/// <param name="info">The info.</param> public async Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated)
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"></exception>
/// <exception cref="System.ArgumentOutOfRangeException">positionTicks</exception>
public async Task OnPlaybackProgress(PlaybackProgressInfo info)
{ {
if (info == null) if (info == null)
{ {
@ -691,7 +693,7 @@ namespace Emby.Server.Implementations.Session
? null ? null
: GetNowPlayingItem(session, info.ItemId); : GetNowPlayingItem(session, info.ItemId);
await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false); await UpdateNowPlayingItem(session, info, libraryItem, !isAutomated).ConfigureAwait(false);
var users = GetUsers(session); var users = GetUsers(session);
@ -703,18 +705,6 @@ namespace Emby.Server.Implementations.Session
} }
} }
if (!string.IsNullOrWhiteSpace(info.LiveStreamId))
{
try
{
await _mediaSourceManager.PingLiveStream(info.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.ErrorException("Error closing live stream", ex);
}
}
EventHelper.FireEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs EventHelper.FireEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs
{ {
Item = libraryItem, Item = libraryItem,

View File

@ -426,18 +426,6 @@ namespace MediaBrowser.Api
{ {
job.ChangeKillTimerIfStarted(); job.ChangeKillTimerIfStarted();
} }
if (!string.IsNullOrWhiteSpace(job.LiveStreamId))
{
try
{
await _mediaSourceManager.PingLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.ErrorException("Error closing live stream", ex);
}
}
} }
/// <summary> /// <summary>

View File

@ -169,7 +169,7 @@ namespace MediaBrowser.Api.Playback
{ {
OpenToken = state.MediaSource.OpenToken OpenToken = state.MediaSource.OpenToken
}, false, cancellationTokenSource.Token).ConfigureAwait(false); }, cancellationTokenSource.Token).ConfigureAwait(false);
EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.RequestedUrl); EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.RequestedUrl);

View File

@ -109,7 +109,7 @@ namespace MediaBrowser.Api.Playback
{ {
var authInfo = _authContext.GetAuthorizationInfo(Request); var authInfo = _authContext.GetAuthorizationInfo(Request);
var result = await _mediaSourceManager.OpenLiveStream(request, true, CancellationToken.None).ConfigureAwait(false); var result = await _mediaSourceManager.OpenLiveStream(request, CancellationToken.None).ConfigureAwait(false);
var profile = request.DeviceProfile; var profile = request.DeviceProfile;
if (profile == null) if (profile == null)

View File

@ -12,7 +12,6 @@ using MediaBrowser.Controller.Library;
namespace MediaBrowser.Api namespace MediaBrowser.Api
{ {
[Route("/Users/{UserId}/Suggestions", "GET", Summary = "Gets items based on a query.")] [Route("/Users/{UserId}/Suggestions", "GET", Summary = "Gets items based on a query.")]
[Route("/Users/{UserId}/Suggestions", "POST", Summary = "Gets items based on a query.")]
public class GetSuggestedItems : IReturn<QueryResult<BaseItem>> public class GetSuggestedItems : IReturn<QueryResult<BaseItem>>
{ {
public string MediaType { get; set; } public string MediaType { get; set; }
@ -21,7 +20,6 @@ namespace MediaBrowser.Api
public bool EnableTotalRecordCount { get; set; } public bool EnableTotalRecordCount { get; set; }
public int? StartIndex { get; set; } public int? StartIndex { get; set; }
public int? Limit { get; set; } public int? Limit { get; set; }
public string Name { get; set; }
public string[] GetMediaTypes() public string[] GetMediaTypes()
{ {
@ -56,13 +54,6 @@ namespace MediaBrowser.Api
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }
public async Task<object> Post(GetSuggestedItems request)
{
var result = await GetResultItems(request).ConfigureAwait(false);
return ToOptimizedResult(result);
}
private async Task<QueryResult<BaseItemDto>> GetResultItems(GetSuggestedItems request) private async Task<QueryResult<BaseItemDto>> GetResultItems(GetSuggestedItems request)
{ {
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@ -86,29 +77,6 @@ namespace MediaBrowser.Api
private QueryResult<BaseItem> GetItems(GetSuggestedItems request, User user, DtoOptions dtoOptions) private QueryResult<BaseItem> GetItems(GetSuggestedItems request, User user, DtoOptions dtoOptions)
{ {
BaseItem similarToItem = null;
if (!string.IsNullOrWhiteSpace(request.Name))
{
// get item by name, then get similar items from that
similarToItem = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
SortBy = new string[] {ItemSortBy.Random},
MediaTypes = request.GetMediaTypes(),
IncludeItemTypes = request.GetIncludeItemTypes(),
IsVirtualItem = false,
Name = request.Name,
Recursive = true,
Limit = 1
}).FirstOrDefault();
if (similarToItem == null)
{
return new QueryResult<BaseItem>();
}
}
return _libraryManager.GetItemsResult(new InternalItemsQuery(user) return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{ {
SortBy = new string[] { ItemSortBy.Random }, SortBy = new string[] { ItemSortBy.Random },
@ -119,8 +87,7 @@ namespace MediaBrowser.Api
Limit = request.Limit, Limit = request.Limit,
DtoOptions = dtoOptions, DtoOptions = dtoOptions,
EnableTotalRecordCount = request.EnableTotalRecordCount, EnableTotalRecordCount = request.EnableTotalRecordCount,
Recursive = true, Recursive = true
SimilarTo = similarToItem
}); });
} }
} }

View File

@ -137,7 +137,6 @@ namespace MediaBrowser.Api
} }
[Route("/Shows/{Id}/Episodes", "GET", Summary = "Gets episodes for a tv season")] [Route("/Shows/{Id}/Episodes", "GET", Summary = "Gets episodes for a tv season")]
[Route("/Shows/Episodes", "POST", Summary = "Gets episodes for a tv season")]
public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions
{ {
/// <summary> /// <summary>
@ -200,12 +199,9 @@ namespace MediaBrowser.Api
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; } public bool? EnableUserData { get; set; }
public string SeriesName { get; set; }
} }
[Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")] [Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
[Route("/Shows/Seasons", "POST", Summary = "Gets seasons for a tv series")]
public class GetSeasons : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions public class GetSeasons : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions
{ {
/// <summary> /// <summary>
@ -248,8 +244,6 @@ namespace MediaBrowser.Api
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; } public bool? EnableUserData { get; set; }
public string SeriesName { get; set; }
} }
/// <summary> /// <summary>
@ -431,7 +425,7 @@ namespace MediaBrowser.Api
{ {
var user = _userManager.GetUserById(request.UserId); var user = _userManager.GetUserById(request.UserId);
var series = GetSeries(request.Id, request.SeriesName, user); var series = GetSeries(request.Id, user);
if (series == null) if (series == null)
{ {
@ -459,33 +453,13 @@ namespace MediaBrowser.Api
}; };
} }
public Task<object> Post(GetSeasons request) private Series GetSeries(string seriesId, User user)
{
return Get(request);
}
public Task<object> Post(GetEpisodes request)
{
return Get(request);
}
private Series GetSeries(string seriesId, string seriesName, User user)
{ {
if (!string.IsNullOrWhiteSpace(seriesId)) if (!string.IsNullOrWhiteSpace(seriesId))
{ {
return _libraryManager.GetItemById(seriesId) as Series; return _libraryManager.GetItemById(seriesId) as Series;
} }
if (!string.IsNullOrWhiteSpace(seriesName))
{
return _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Name = seriesName,
IncludeItemTypes = new string[] { typeof(Series).Name }
}).OfType<Series>().FirstOrDefault();
}
return null; return null;
} }
@ -508,7 +482,7 @@ namespace MediaBrowser.Api
} }
else if (request.Season.HasValue) else if (request.Season.HasValue)
{ {
var series = GetSeries(request.Id, request.SeriesName, user); var series = GetSeries(request.Id, user);
if (series == null) if (series == null)
{ {
@ -528,7 +502,7 @@ namespace MediaBrowser.Api
} }
else else
{ {
var series = GetSeries(request.Id, request.SeriesName, user); var series = GetSeries(request.Id, user);
if (series == null) if (series == null)
{ {

View File

@ -68,10 +68,9 @@ namespace MediaBrowser.Controller.Library
/// Opens the media source. /// Opens the media source.
/// </summary> /// </summary>
/// <param name="request">The request.</param> /// <param name="request">The request.</param>
/// <param name="enableAutoClose">if set to <c>true</c> [enable automatic close].</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<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken); Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the live stream. /// Gets the live stream.
@ -83,14 +82,6 @@ namespace MediaBrowser.Controller.Library
Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken); Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken);
/// <summary>
/// Pings the media source.
/// </summary>
/// <param name="id">The live stream identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task PingLiveStream(string id, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Closes the media source. /// Closes the media source.
/// </summary> /// </summary>

View File

@ -99,6 +99,8 @@ namespace MediaBrowser.Controller.Session
/// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentNullException"></exception>
Task OnPlaybackProgress(PlaybackProgressInfo info); Task OnPlaybackProgress(PlaybackProgressInfo info);
Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated);
/// <summary> /// <summary>
/// Used to report that playback has ended for an item /// Used to report that playback has ended for an item
/// </summary> /// </summary>

View File

@ -257,7 +257,7 @@ namespace MediaBrowser.Controller.Session
try try
{ {
await _sessionManager.OnPlaybackProgress(progressInfo).ConfigureAwait(false); await _sessionManager.OnPlaybackProgress(progressInfo, true).ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -356,7 +356,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
OpenToken = state.MediaSource.OpenToken OpenToken = state.MediaSource.OpenToken
}, false, cancellationToken).ConfigureAwait(false); }, cancellationToken).ConfigureAwait(false);
EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, null); EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, null);