Display client version in the dashboard

This commit is contained in:
Luke Pulverenti 2013-07-09 12:11:16 -04:00
parent 48265fefa4
commit 66624293ac
21 changed files with 266 additions and 144 deletions

View File

@ -286,13 +286,21 @@ namespace MediaBrowser.Api
} }
} }
var deviceId = auth["DeviceId"]; string deviceId;
var device = auth["Device"]; string device;
var client = auth["Client"]; string client;
string version;
if (!string.IsNullOrEmpty(client) && !string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(device)) auth.TryGetValue("DeviceId", out deviceId);
auth.TryGetValue("Device", out device);
auth.TryGetValue("Client", out client);
auth.TryGetValue("Version", out version);
version = version ?? "0.0.0.0";
if (!string.IsNullOrEmpty(client) && !string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(device) && !string.IsNullOrEmpty(version))
{ {
SessionManager.LogConnectionActivity(client, deviceId, device, user); SessionManager.LogConnectionActivity(client, version, deviceId, device, user);
} }
} }
} }

View File

@ -1,6 +1,5 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session; using MediaBrowser.Model.Session;
@ -106,6 +105,31 @@ namespace MediaBrowser.Api
public PlayCommand PlayCommand { get; set; } public PlayCommand PlayCommand { get; set; }
} }
[Route("/Sessions/{Id}/Playing/{Command}", "POST")]
[Api(("Issues a playstate command to a client"))]
public class SendPlaystateCommand : IReturnVoid
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public Guid Id { get; set; }
/// <summary>
/// Gets or sets the position to seek to
/// </summary>
[ApiMember(Name = "SeekPosition", Description = "The position to seek to.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public long? SeekPosition { get; set; }
/// <summary>
/// Gets or sets the play command.
/// </summary>
/// <value>The play command.</value>
[ApiMember(Name = "Command", Description = "The command to send - stop, pause, unpause, nexttrack, previoustrack, seek.", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public PlaystateCommand Command { get; set; }
}
/// <summary> /// <summary>
/// Class SessionsService /// Class SessionsService
/// </summary> /// </summary>
@ -142,6 +166,56 @@ namespace MediaBrowser.Api
return ToOptimizedResult(result.Select(SessionInfoDtoBuilder.GetSessionInfoDto).ToList()); return ToOptimizedResult(result.Select(SessionInfoDtoBuilder.GetSessionInfoDto).ToList());
} }
public void Post(SendPlaystateCommand request)
{
var task = SendPlaystateCommand(request);
Task.WaitAll(task);
}
private async Task SendPlaystateCommand(SendPlaystateCommand request)
{
var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id);
if (session == null)
{
throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id));
}
if (!session.SupportsRemoteControl)
{
throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id));
}
var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open);
if (socket != null)
{
try
{
await socket.SendAsync(new WebSocketMessage<PlayStateRequest>
{
MessageType = "Playstate",
Data = new PlayStateRequest
{
Command = request.Command,
SeekPosition = request.SeekPosition
}
}, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.ErrorException("Error sending web socket message", ex);
}
}
else
{
throw new InvalidOperationException("The requested session does not have an open web socket.");
}
}
/// <summary> /// <summary>
/// Posts the specified request. /// Posts the specified request.
/// </summary> /// </summary>

View File

@ -586,6 +586,25 @@ namespace MediaBrowser.Api.UserLibrary
Task.WaitAll(task); Task.WaitAll(task);
} }
private SessionInfo GetSession()
{
var auth = RequestFilterAttribute.GetAuthorization(RequestContext);
string deviceId;
string client;
string version;
auth.TryGetValue("DeviceId", out deviceId);
auth.TryGetValue("Client", out client);
auth.TryGetValue("Version", out version);
version = version ?? "0.0.0.0";
return _sessionManager.Sessions.First(i => string.Equals(i.DeviceId, deviceId) &&
string.Equals(i.Client, client) &&
string.Equals(i.ApplicationVersion, version));
}
/// <summary> /// <summary>
/// Posts the specified request. /// Posts the specified request.
/// </summary> /// </summary>
@ -596,12 +615,7 @@ namespace MediaBrowser.Api.UserLibrary
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
var auth = RequestFilterAttribute.GetAuthorization(RequestContext); _sessionManager.OnPlaybackStart(item, GetSession().Id);
if (auth != null)
{
_sessionManager.OnPlaybackStart(user, item, auth["Client"], auth["DeviceId"], auth["Device"] ?? string.Empty);
}
} }
/// <summary> /// <summary>
@ -614,14 +628,9 @@ namespace MediaBrowser.Api.UserLibrary
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
var auth = RequestFilterAttribute.GetAuthorization(RequestContext); var task = _sessionManager.OnPlaybackProgress(item, request.PositionTicks, request.IsPaused, GetSession().Id);
if (auth != null) Task.WaitAll(task);
{
var task = _sessionManager.OnPlaybackProgress(user, item, request.PositionTicks, request.IsPaused, auth["Client"], auth["DeviceId"], auth["Device"] ?? string.Empty);
Task.WaitAll(task);
}
} }
/// <summary> /// <summary>
@ -634,14 +643,9 @@ namespace MediaBrowser.Api.UserLibrary
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
var auth = RequestFilterAttribute.GetAuthorization(RequestContext); var task = _sessionManager.OnPlaybackStopped(item, request.PositionTicks, GetSession().Id);
if (auth != null) Task.WaitAll(task);
{
var task = _sessionManager.OnPlaybackStopped(user, item, request.PositionTicks, auth["Client"], auth["DeviceId"], auth["Device"] ?? string.Empty);
Task.WaitAll(task);
}
} }
/// <summary> /// <summary>

View File

@ -381,9 +381,9 @@ namespace MediaBrowser.Controller.Dto
if (parentWithImage != null) if (parentWithImage != null)
{ {
dto.ParentLogoItemId = GetClientItemId(parentWithImage); dto.ParentArtItemId = GetClientItemId(parentWithImage);
dto.ParentLogoImageTag = GetImageCacheTag(parentWithImage, ImageType.Art, parentWithImage.GetImage(ImageType.Art)); dto.ParentArtImageTag = GetImageCacheTag(parentWithImage, ImageType.Art, parentWithImage.GetImage(ImageType.Art));
} }
} }

View File

@ -28,7 +28,8 @@ namespace MediaBrowser.Controller.Dto
NowViewingContext = session.NowViewingContext, NowViewingContext = session.NowViewingContext,
NowViewingItemId = session.NowViewingItemId, NowViewingItemId = session.NowViewingItemId,
NowViewingItemName = session.NowViewingItemName, NowViewingItemName = session.NowViewingItemName,
NowViewingItemType = session.NowViewingItemType NowViewingItemType = session.NowViewingItemType,
ApplicationVersion = session.ApplicationVersion
}; };
if (session.NowPlayingItem != null) if (session.NowPlayingItem != null)

View File

@ -70,7 +70,7 @@
<Compile Include="..\SharedVersion.cs"> <Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link> <Link>Properties\SharedVersion.cs</Link>
</Compile> </Compile>
<Compile Include="Configuration\IServerConfigurationManager.cs" /> <Compile Include="Notifications\Configuration\IServerConfigurationManager.cs" />
<Compile Include="Dto\SessionInfoDtoBuilder.cs" /> <Compile Include="Dto\SessionInfoDtoBuilder.cs" />
<Compile Include="Entities\Audio\MusicAlbumDisc.cs" /> <Compile Include="Entities\Audio\MusicAlbumDisc.cs" />
<Compile Include="Entities\Audio\MusicGenre.cs" /> <Compile Include="Entities\Audio\MusicGenre.cs" />

View File

@ -36,49 +36,42 @@ namespace MediaBrowser.Controller.Session
/// Logs the user activity. /// Logs the user activity.
/// </summary> /// </summary>
/// <param name="clientType">Type of the client.</param> /// <param name="clientType">Type of the client.</param>
/// <param name="appVersion">The app version.</param>
/// <param name="deviceId">The device id.</param> /// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param> /// <param name="deviceName">Name of the device.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">user</exception> /// <exception cref="System.ArgumentNullException">user</exception>
Task LogConnectionActivity(string clientType, string deviceId, string deviceName, User user); Task<SessionInfo> LogConnectionActivity(string clientType, string appVersion, string deviceId, string deviceName, User user);
/// <summary> /// <summary>
/// Used to report that playback has started for an item /// Used to report that playback has started for an item
/// </summary> /// </summary>
/// <param name="user">The user.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="clientType">Type of the client.</param> /// <param name="sessionId">The session id.</param>
/// <param name="deviceId">The device id.</param> /// <returns>Task.</returns>
/// <param name="deviceName">Name of the device.</param>
/// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentNullException"></exception>
Task OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName); Task OnPlaybackStart(BaseItem item, Guid sessionId);
/// <summary> /// <summary>
/// Used to report playback progress for an item /// Used to report playback progress for an item
/// </summary> /// </summary>
/// <param name="user">The user.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="positionTicks">The position ticks.</param> /// <param name="positionTicks">The position ticks.</param>
/// <param name="isPaused">if set to <c>true</c> [is paused].</param> /// <param name="isPaused">if set to <c>true</c> [is paused].</param>
/// <param name="clientType">Type of the client.</param> /// <param name="sessionId">The session id.</param>
/// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentNullException"></exception>
Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, bool isPaused, string clientType, string deviceId, string deviceName); Task OnPlaybackProgress(BaseItem item, long? positionTicks, bool isPaused, Guid sessionId);
/// <summary> /// <summary>
/// Used to report that playback has ended for an item /// Used to report that playback has ended for an item
/// </summary> /// </summary>
/// <param name="user">The user.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="positionTicks">The position ticks.</param> /// <param name="positionTicks">The position ticks.</param>
/// <param name="clientType">Type of the client.</param> /// <param name="sessionId">The session id.</param>
/// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentNullException"></exception>
Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, string clientType, string deviceId, string deviceName); Task OnPlaybackStopped(BaseItem item, long? positionTicks, Guid sessionId);
} }
} }

View File

@ -101,6 +101,12 @@ namespace MediaBrowser.Controller.Session
/// <value>The web socket.</value> /// <value>The web socket.</value>
public List<IWebSocketConnection> WebSockets { get; set; } public List<IWebSocketConnection> WebSockets { get; set; }
/// <summary>
/// Gets or sets the application version.
/// </summary>
/// <value>The application version.</value>
public string ApplicationVersion { get; set; }
/// <summary> /// <summary>
/// Gets a value indicating whether this instance is active. /// Gets a value indicating whether this instance is active.
/// </summary> /// </summary>

View File

@ -268,6 +268,9 @@
<Compile Include="..\MediaBrowser.Model\Querying\ThemeSongsResult.cs"> <Compile Include="..\MediaBrowser.Model\Querying\ThemeSongsResult.cs">
<Link>Querying\ThemeSongsResult.cs</Link> <Link>Querying\ThemeSongsResult.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\Querying\UserQuery.cs">
<Link>Querying\UserQuery.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\Search\SearchHint.cs"> <Compile Include="..\MediaBrowser.Model\Search\SearchHint.cs">
<Link>Search\SearchHint.cs</Link> <Link>Search\SearchHint.cs</Link>
</Compile> </Compile>
@ -286,8 +289,8 @@
<Compile Include="..\MediaBrowser.Model\Session\PlayRequest.cs"> <Compile Include="..\MediaBrowser.Model\Session\PlayRequest.cs">
<Link>Session\PlayRequest.cs</Link> <Link>Session\PlayRequest.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\Session\PlaystateRequest.cs"> <Compile Include="..\MediaBrowser.Model\Session\PlaystateCommand.cs">
<Link>Session\PlaystateRequest.cs</Link> <Link>Session\PlaystateCommand.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\Session\SessionInfoDto.cs"> <Compile Include="..\MediaBrowser.Model\Session\SessionInfoDto.cs">
<Link>Session\SessionInfoDto.cs</Link> <Link>Session\SessionInfoDto.cs</Link>

View File

@ -100,6 +100,12 @@ namespace MediaBrowser.Model.ApiClient
/// <returns>Task{UserDto[]}.</returns> /// <returns>Task{UserDto[]}.</returns>
Task<UserDto[]> GetUsersAsync(); Task<UserDto[]> GetUsersAsync();
/// <summary>
/// Gets the public users async.
/// </summary>
/// <returns>Task{UserDto[]}.</returns>
Task<UserDto[]> GetPublicUsersAsync();
/// <summary> /// <summary>
/// Gets active client sessions. /// Gets active client sessions.
/// </summary> /// </summary>
@ -358,6 +364,14 @@ namespace MediaBrowser.Model.ApiClient
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task SendBrowseCommandAsync(string sessionId, string itemId, string itemName, string itemType, string context); Task SendBrowseCommandAsync(string sessionId, string itemId, string itemName, string itemType, string context);
/// <summary>
/// Sends the playstate command async.
/// </summary>
/// <param name="sessionId">The session id.</param>
/// <param name="request">The request.</param>
/// <returns>Task.</returns>
Task SendPlaystateCommandAsync(string sessionId, PlayStateRequest request);
/// <summary> /// <summary>
/// Sends the play command async. /// Sends the play command async.
/// </summary> /// </summary>

View File

@ -72,9 +72,10 @@
<Compile Include="Entities\BaseItemInfo.cs" /> <Compile Include="Entities\BaseItemInfo.cs" />
<Compile Include="Querying\NextUpQuery.cs" /> <Compile Include="Querying\NextUpQuery.cs" />
<Compile Include="Querying\SimilarItemsQuery.cs" /> <Compile Include="Querying\SimilarItemsQuery.cs" />
<Compile Include="Querying\UserQuery.cs" />
<Compile Include="Session\BrowseRequest.cs" /> <Compile Include="Session\BrowseRequest.cs" />
<Compile Include="Session\PlayRequest.cs" /> <Compile Include="Session\PlayRequest.cs" />
<Compile Include="Session\PlaystateRequest.cs" /> <Compile Include="Session\PlaystateCommand.cs" />
<Compile Include="Entities\ImageDownloadOptions.cs" /> <Compile Include="Entities\ImageDownloadOptions.cs" />
<Compile Include="Logging\ILogManager.cs" /> <Compile Include="Logging\ILogManager.cs" />
<Compile Include="MediaInfo\BlurayDiscInfo.cs" /> <Compile Include="MediaInfo\BlurayDiscInfo.cs" />

View File

@ -0,0 +1,9 @@

namespace MediaBrowser.Model.Querying
{
public class UserQuery
{
public bool? IsHidden { get; set; }
public bool? IsDisabled { get; set; }
}
}

View File

@ -1,25 +1,6 @@
 
namespace MediaBrowser.Model.Session namespace MediaBrowser.Model.Session
{ {
/// <summary>
/// Class PlaystateRequest
/// </summary>
public class PlaystateRequest
{
/// <summary>
/// Gets or sets the command.
/// </summary>
/// <value>The command.</value>
public PlaystateCommand Command { get; set; }
/// <summary>
/// Gets or sets the seek position.
/// Only applicable to seek commands.
/// </summary>
/// <value>The seek position.</value>
public long? SeekPosition { get; set; }
}
/// <summary> /// <summary>
/// Enum PlaystateCommand /// Enum PlaystateCommand
/// </summary> /// </summary>
@ -50,4 +31,11 @@ namespace MediaBrowser.Model.Session
/// </summary> /// </summary>
Seek Seek
} }
public class PlayStateRequest
{
public PlaystateCommand Command { get; set; }
public long? SeekPosition { get; set; }
}
} }

View File

@ -22,6 +22,12 @@ namespace MediaBrowser.Model.Session
/// </summary> /// </summary>
/// <value>The name of the user.</value> /// <value>The name of the user.</value>
public string UserName { get; set; } public string UserName { get; set; }
/// <summary>
/// Gets or sets the application version.
/// </summary>
/// <value>The application version.</value>
public string ApplicationVersion { get; set; }
/// <summary> /// <summary>
/// Gets or sets the type of the client. /// Gets or sets the type of the client.

View File

@ -121,7 +121,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
} }
} }
} }
/// <summary> /// <summary>
/// Creates the triggers that define when the task will run /// Creates the triggers that define when the task will run
/// </summary> /// </summary>
@ -148,13 +148,15 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
var numComplete = 0; var numComplete = 0;
var failHistoryPath = Path.Combine(_kernel.FFMpegManager.VideoImagesDataPath, "failures.json"); var failHistoryPath = Path.Combine(_kernel.FFMpegManager.VideoImagesDataPath, "failures.txt");
List<string> previouslyFailedImages; List<string> previouslyFailedImages;
try try
{ {
previouslyFailedImages = _jsonSerializer.DeserializeFromFile<List<string>>(failHistoryPath); previouslyFailedImages = File.ReadAllText(failHistoryPath)
.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
.ToList();
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
@ -184,7 +186,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
Directory.CreateDirectory(parentPath); Directory.CreateDirectory(parentPath);
} }
_jsonSerializer.SerializeToFile(previouslyFailedImages, failHistoryPath); File.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray()));
} }
numComplete++; numComplete++;

View File

@ -94,13 +94,32 @@ namespace MediaBrowser.Server.Implementations.Session
/// Logs the user activity. /// Logs the user activity.
/// </summary> /// </summary>
/// <param name="clientType">Type of the client.</param> /// <param name="clientType">Type of the client.</param>
/// <param name="appVersion">The app version.</param>
/// <param name="deviceId">The device id.</param> /// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param> /// <param name="deviceName">Name of the device.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.UnauthorizedAccessException"></exception>
/// <exception cref="System.ArgumentNullException">user</exception> /// <exception cref="System.ArgumentNullException">user</exception>
public Task LogConnectionActivity(string clientType, string deviceId, string deviceName, User user) public async Task<SessionInfo> LogConnectionActivity(string clientType, string appVersion, string deviceId, string deviceName, User user)
{ {
if (string.IsNullOrEmpty(clientType))
{
throw new ArgumentNullException("clientType");
}
if (string.IsNullOrEmpty(appVersion))
{
throw new ArgumentNullException("appVersion");
}
if (string.IsNullOrEmpty(deviceId))
{
throw new ArgumentNullException("deviceId");
}
if (string.IsNullOrEmpty(deviceName))
{
throw new ArgumentNullException("deviceName");
}
if (user != null && user.Configuration.IsDisabled) if (user != null && user.Configuration.IsDisabled)
{ {
throw new UnauthorizedAccessException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name)); throw new UnauthorizedAccessException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name));
@ -108,11 +127,13 @@ namespace MediaBrowser.Server.Implementations.Session
var activityDate = DateTime.UtcNow; var activityDate = DateTime.UtcNow;
GetConnection(clientType, deviceId, deviceName, user).LastActivityDate = activityDate; var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, user);
session.LastActivityDate = activityDate;
if (user == null) if (user == null)
{ {
return _trueTaskResult; return session;
} }
var lastActivityDate = user.LastActivityDate; var lastActivityDate = user.LastActivityDate;
@ -122,50 +143,42 @@ namespace MediaBrowser.Server.Implementations.Session
// Don't log in the db anymore frequently than 10 seconds // Don't log in the db anymore frequently than 10 seconds
if (lastActivityDate.HasValue && (activityDate - lastActivityDate.Value).TotalSeconds < 10) if (lastActivityDate.HasValue && (activityDate - lastActivityDate.Value).TotalSeconds < 10)
{ {
return _trueTaskResult; return session;
} }
// Save this directly. No need to fire off all the events for this. // Save this directly. No need to fire off all the events for this.
return _userRepository.SaveUser(user, CancellationToken.None); await _userRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false);
return session;
} }
/// <summary> /// <summary>
/// Updates the now playing item id. /// Updates the now playing item id.
/// </summary> /// </summary>
/// <param name="user">The user.</param> /// <param name="session">The session.</param>
/// <param name="clientType">Type of the client.</param>
/// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="isPaused">if set to <c>true</c> [is paused].</param> /// <param name="isPaused">if set to <c>true</c> [is paused].</param>
/// <param name="currentPositionTicks">The current position ticks.</param> /// <param name="currentPositionTicks">The current position ticks.</param>
private void UpdateNowPlayingItemId(User user, string clientType, string deviceId, string deviceName, BaseItem item, bool isPaused, long? currentPositionTicks = null) private void UpdateNowPlayingItem(SessionInfo session, BaseItem item, bool isPaused, long? currentPositionTicks = null)
{ {
var conn = GetConnection(clientType, deviceId, deviceName, user); session.IsPaused = isPaused;
session.NowPlayingPositionTicks = currentPositionTicks;
conn.IsPaused = isPaused; session.NowPlayingItem = item;
conn.NowPlayingPositionTicks = currentPositionTicks; session.LastActivityDate = DateTime.UtcNow;
conn.NowPlayingItem = item;
conn.LastActivityDate = DateTime.UtcNow;
} }
/// <summary> /// <summary>
/// Removes the now playing item id. /// Removes the now playing item id.
/// </summary> /// </summary>
/// <param name="user">The user.</param> /// <param name="session">The session.</param>
/// <param name="clientType">Type of the client.</param>
/// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
private void RemoveNowPlayingItemId(User user, string clientType, string deviceId, string deviceName, BaseItem item) private void RemoveNowPlayingItem(SessionInfo session, BaseItem item)
{ {
var conn = GetConnection(clientType, deviceId, deviceName, user); if (session.NowPlayingItem != null && session.NowPlayingItem.Id == item.Id)
if (conn.NowPlayingItem != null && conn.NowPlayingItem.Id == item.Id)
{ {
conn.NowPlayingItem = null; session.NowPlayingItem = null;
conn.NowPlayingPositionTicks = null; session.NowPlayingPositionTicks = null;
conn.IsPaused = null; session.IsPaused = null;
} }
} }
@ -173,23 +186,24 @@ namespace MediaBrowser.Server.Implementations.Session
/// Gets the connection. /// Gets the connection.
/// </summary> /// </summary>
/// <param name="clientType">Type of the client.</param> /// <param name="clientType">Type of the client.</param>
/// <param name="appVersion">The app version.</param>
/// <param name="deviceId">The device id.</param> /// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param> /// <param name="deviceName">Name of the device.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <returns>SessionInfo.</returns> /// <returns>SessionInfo.</returns>
private SessionInfo GetConnection(string clientType, string deviceId, string deviceName, User user) private SessionInfo GetSessionInfo(string clientType, string appVersion, string deviceId, string deviceName, User user)
{ {
var key = clientType + deviceId; var key = clientType + deviceId + appVersion;
var connection = _activeConnections.GetOrAdd(key, keyName => new SessionInfo var connection = _activeConnections.GetOrAdd(key, keyName => new SessionInfo
{ {
Client = clientType, Client = clientType,
DeviceId = deviceId, DeviceId = deviceId,
ApplicationVersion = appVersion,
Id = Guid.NewGuid() Id = Guid.NewGuid()
}); });
connection.DeviceName = deviceName; connection.DeviceName = deviceName;
connection.User = user; connection.User = user;
return connection; return connection;
@ -198,28 +212,25 @@ namespace MediaBrowser.Server.Implementations.Session
/// <summary> /// <summary>
/// Used to report that playback has started for an item /// Used to report that playback has started for an item
/// </summary> /// </summary>
/// <param name="user">The user.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="clientType">Type of the client.</param> /// <param name="sessionId">The session id.</param>
/// <param name="deviceId">The device id.</param> /// <returns>Task.</returns>
/// <param name="deviceName">Name of the device.</param> /// <exception cref="System.ArgumentNullException"></exception>
/// <exception cref="System.ArgumentNullException"> public async Task OnPlaybackStart(BaseItem item, Guid sessionId)
/// </exception>
public async Task OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName)
{ {
if (user == null)
{
throw new ArgumentNullException();
}
if (item == null) if (item == null)
{ {
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, false); var session = Sessions.First(i => i.Id.Equals(sessionId));
UpdateNowPlayingItem(session, item, false);
var key = item.GetUserDataKey(); var key = item.GetUserDataKey();
var user = session.User;
var data = _userDataRepository.GetUserData(user.Id, key); var data = _userDataRepository.GetUserData(user.Id, key);
data.PlayCount++; data.PlayCount++;
@ -248,27 +259,25 @@ namespace MediaBrowser.Server.Implementations.Session
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="positionTicks">The position ticks.</param> /// <param name="positionTicks">The position ticks.</param>
/// <param name="isPaused">if set to <c>true</c> [is paused].</param> /// <param name="isPaused">if set to <c>true</c> [is paused].</param>
/// <param name="clientType">Type of the client.</param> /// <param name="sessionId">The session id.</param>
/// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"> /// <exception cref="System.ArgumentNullException">
/// </exception> /// </exception>
public async Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, bool isPaused, string clientType, string deviceId, string deviceName) public async Task OnPlaybackProgress(BaseItem item, long? positionTicks, bool isPaused, Guid sessionId)
{ {
if (user == null)
{
throw new ArgumentNullException();
}
if (item == null) if (item == null)
{ {
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, isPaused, positionTicks); var session = Sessions.First(i => i.Id.Equals(sessionId));
UpdateNowPlayingItem(session, item, isPaused, positionTicks);
var key = item.GetUserDataKey(); var key = item.GetUserDataKey();
var user = session.User;
if (positionTicks.HasValue) if (positionTicks.HasValue)
{ {
var data = _userDataRepository.GetUserData(user.Id, key); var data = _userDataRepository.GetUserData(user.Id, key);
@ -282,36 +291,33 @@ namespace MediaBrowser.Server.Implementations.Session
Item = item, Item = item,
User = user, User = user,
PlaybackPositionTicks = positionTicks PlaybackPositionTicks = positionTicks
}, _logger); }, _logger);
} }
/// <summary> /// <summary>
/// Used to report that playback has ended for an item /// Used to report that playback has ended for an item
/// </summary> /// </summary>
/// <param name="user">The user.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="positionTicks">The position ticks.</param> /// <param name="positionTicks">The position ticks.</param>
/// <param name="clientType">Type of the client.</param> /// <param name="sessionId">The session id.</param>
/// <param name="deviceId">The device id.</param>
/// <param name="deviceName">Name of the device.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"> /// <exception cref="System.ArgumentNullException"></exception>
/// </exception> public async Task OnPlaybackStopped(BaseItem item, long? positionTicks, Guid sessionId)
public async Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, string clientType, string deviceId, string deviceName)
{ {
if (user == null)
{
throw new ArgumentNullException();
}
if (item == null) if (item == null)
{ {
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
RemoveNowPlayingItemId(user, clientType, deviceId, deviceName, item); var session = Sessions.First(i => i.Id.Equals(sessionId));
RemoveNowPlayingItem(session, item);
var key = item.GetUserDataKey(); var key = item.GetUserDataKey();
var user = session.User;
var data = _userDataRepository.GetUserData(user.Id, key); var data = _userDataRepository.GetUserData(user.Id, key);
if (positionTicks.HasValue) if (positionTicks.HasValue)

View File

@ -103,7 +103,7 @@ namespace MediaBrowser.Server.Implementations.Session
{ {
var item = DtoBuilder.GetItemByClientId(message.Data, _userManager, _libraryManager); var item = DtoBuilder.GetItemByClientId(message.Data, _userManager, _libraryManager);
_sessionManager.OnPlaybackStart(_userManager.GetUserById(session.User.Id), item, session.Client, session.DeviceId, session.DeviceName); _sessionManager.OnPlaybackStart(item, session.Id);
} }
} }
else if (string.Equals(message.MessageType, "PlaybackProgress", StringComparison.OrdinalIgnoreCase)) else if (string.Equals(message.MessageType, "PlaybackProgress", StringComparison.OrdinalIgnoreCase))
@ -130,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.Session
var isPaused = vals.Length > 2 && string.Equals(vals[2], "true", StringComparison.OrdinalIgnoreCase); var isPaused = vals.Length > 2 && string.Equals(vals[2], "true", StringComparison.OrdinalIgnoreCase);
_sessionManager.OnPlaybackProgress(_userManager.GetUserById(session.User.Id), item, positionTicks, isPaused, session.Client, session.DeviceId, session.DeviceName); _sessionManager.OnPlaybackProgress(item, positionTicks, isPaused, session.Id);
} }
} }
else if (string.Equals(message.MessageType, "PlaybackStopped", StringComparison.OrdinalIgnoreCase)) else if (string.Equals(message.MessageType, "PlaybackStopped", StringComparison.OrdinalIgnoreCase))
@ -155,7 +155,7 @@ namespace MediaBrowser.Server.Implementations.Session
} }
} }
_sessionManager.OnPlaybackStopped(_userManager.GetUserById(session.User.Id), item, positionTicks, session.Client, session.DeviceId, session.DeviceName); _sessionManager.OnPlaybackStopped(item, positionTicks, session.Id);
} }
} }

View File

@ -512,6 +512,12 @@ namespace MediaBrowser.WebDashboard.Api
var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine); var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
var versionString = string.Format("window.dashboardVersion='{0}';", GetType().Assembly.GetName().Version);
var versionBytes = Encoding.UTF8.GetBytes(versionString);
await memoryStream.WriteAsync(versionBytes, 0, versionBytes.Length).ConfigureAwait(false);
await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
await AppendResource(memoryStream, "thirdparty/autoNumeric.js", newLineBytes).ConfigureAwait(false); await AppendResource(memoryStream, "thirdparty/autoNumeric.js", newLineBytes).ConfigureAwait(false);
await AppendResource(memoryStream, "thirdparty/html5slider.js", newLineBytes).ConfigureAwait(false); await AppendResource(memoryStream, "thirdparty/html5slider.js", newLineBytes).ConfigureAwait(false);

View File

@ -10,8 +10,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
* @param {String} serverHostName * @param {String} serverHostName
* @param {String} serverPortNumber * @param {String} serverPortNumber
* @param {String} clientName * @param {String} clientName
* @param {String} applicationVersion
*/ */
return function (serverProtocol, serverHostName, serverPortNumber, clientName) { return function (serverProtocol, serverHostName, serverPortNumber, clientName, applicationVersion) {
if (!serverProtocol) { if (!serverProtocol) {
throw new Error("Must supply a serverProtocol, e.g. http:"); throw new Error("Must supply a serverProtocol, e.g. http:");
@ -120,7 +121,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
if (clientName) { if (clientName) {
var auth = 'MediaBrowser Client="' + clientName + '", Device="' + deviceName + '", DeviceId="' + deviceId + '"'; var auth = 'MediaBrowser Client="' + clientName + '", Device="' + deviceName + '", DeviceId="' + deviceId + '", Version="' + applicationVersion + '"';
if (currentUserId) { if (currentUserId) {
auth += ', UserId="' + currentUserId + '"'; auth += ', UserId="' + currentUserId + '"';
@ -3277,11 +3278,11 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
/** /**
* Provides a friendly way to create an api client instance using information from the browser's current url * Provides a friendly way to create an api client instance using information from the browser's current url
*/ */
MediaBrowser.ApiClient.create = function (clientName) { MediaBrowser.ApiClient.create = function (clientName, applicationVersion) {
var loc = window.location; var loc = window.location;
return new MediaBrowser.ApiClient(loc.protocol, loc.hostname, loc.port, clientName); return new MediaBrowser.ApiClient(loc.protocol, loc.hostname, loc.port, clientName, applicationVersion);
}; };
/** /**

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.139" targetFramework="net45" /> <package id="MediaBrowser.ApiClient.Javascript" version="3.0.141" targetFramework="net45" />
<package id="ServiceStack.Common" version="3.9.54" targetFramework="net45" /> <package id="ServiceStack.Common" version="3.9.54" targetFramework="net45" />
<package id="ServiceStack.Text" version="3.9.54" targetFramework="net45" /> <package id="ServiceStack.Text" version="3.9.54" targetFramework="net45" />
</packages> </packages>