mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
restored request logging
This commit is contained in:
parent
656a9ddaec
commit
4d083b618d
118
MediaBrowser.Api/BaseApiService.cs
Normal file
118
MediaBrowser.Api/BaseApiService.cs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Model.Connectivity;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Server.Implementations.HttpServer;
|
||||||
|
using ServiceStack.Common.Web;
|
||||||
|
using ServiceStack.ServiceHost;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class BaseApiService
|
||||||
|
/// </summary>
|
||||||
|
[RequestFilter]
|
||||||
|
public class BaseApiService : BaseRestService
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class RequestFilterAttribute
|
||||||
|
/// </summary>
|
||||||
|
public class RequestFilterAttribute : Attribute, IHasRequestFilter
|
||||||
|
{
|
||||||
|
//This property will be resolved by the IoC container
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the user manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The user manager.</value>
|
||||||
|
public IUserManager UserManager { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the logger.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The logger.</value>
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The request filter is executed before the service.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The http request wrapper</param>
|
||||||
|
/// <param name="response">The http response wrapper</param>
|
||||||
|
/// <param name="requestDto">The request DTO</param>
|
||||||
|
public void RequestFilter(IHttpRequest request, IHttpResponse response, object requestDto)
|
||||||
|
{
|
||||||
|
//This code is executed before the service
|
||||||
|
|
||||||
|
var auth = GetAuthorization(request);
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
{
|
||||||
|
var user = UserManager.GetUserById(new Guid(auth["UserId"]));
|
||||||
|
|
||||||
|
ClientType clientType;
|
||||||
|
|
||||||
|
Enum.TryParse(auth["Client"] ?? string.Empty, out clientType);
|
||||||
|
|
||||||
|
UserManager.LogUserActivity(user, clientType, auth["DeviceId"], auth["Device"] ?? string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the auth.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpReq">The HTTP req.</param>
|
||||||
|
/// <returns>Dictionary{System.StringSystem.String}.</returns>
|
||||||
|
public static Dictionary<string, string> GetAuthorization(IHttpRequest httpReq)
|
||||||
|
{
|
||||||
|
var auth = httpReq.Headers[HttpHeaders.Authorization];
|
||||||
|
if (auth == null) return null;
|
||||||
|
|
||||||
|
var parts = auth.Split(' ');
|
||||||
|
|
||||||
|
// There should be at least to parts
|
||||||
|
if (parts.Length < 2) return null;
|
||||||
|
|
||||||
|
// It has to be a digest request
|
||||||
|
if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove uptil the first space
|
||||||
|
auth = auth.Substring(auth.IndexOf(' '));
|
||||||
|
parts = auth.Split(',');
|
||||||
|
|
||||||
|
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
foreach (var item in parts)
|
||||||
|
{
|
||||||
|
var param = item.Trim().Split(new[] { '=' }, 2);
|
||||||
|
result.Add(param[0], param[1].Trim(new[] { '"' }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A new shallow copy of this filter is used on every request.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>IHasRequestFilter.</returns>
|
||||||
|
public IHasRequestFilter Copy()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order in which Request Filters are executed.
|
||||||
|
/// <0 Executed before global request filters
|
||||||
|
/// >0 Executed after global request filters
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The priority.</value>
|
||||||
|
public int Priority
|
||||||
|
{
|
||||||
|
get { return 0; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -75,7 +75,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class EnvironmentService
|
/// Class EnvironmentService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EnvironmentService : BaseRestService
|
public class EnvironmentService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _network manager
|
/// The _network manager
|
||||||
|
@ -150,7 +150,7 @@ namespace MediaBrowser.Api.Images
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class ImageService
|
/// Class ImageService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ImageService : BaseRestService
|
public class ImageService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _user manager
|
/// The _user manager
|
||||||
|
@ -98,7 +98,7 @@ namespace MediaBrowser.Api.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class LibraryService
|
/// Class LibraryService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LibraryService : BaseRestService
|
public class LibraryService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _app host
|
/// The _app host
|
||||||
|
@ -129,7 +129,7 @@ namespace MediaBrowser.Api.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class LibraryStructureService
|
/// Class LibraryStructureService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LibraryStructureService : BaseRestService
|
public class LibraryStructureService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _app paths
|
/// The _app paths
|
||||||
|
@ -40,7 +40,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class CulturesService
|
/// Class CulturesService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LocalizationService : BaseRestService
|
public class LocalizationService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the specified request.
|
/// Gets the specified request.
|
||||||
|
@ -81,6 +81,7 @@
|
|||||||
<Compile Include="..\SharedVersion.cs">
|
<Compile Include="..\SharedVersion.cs">
|
||||||
<Link>Properties\SharedVersion.cs</Link>
|
<Link>Properties\SharedVersion.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="BaseApiService.cs" />
|
||||||
<Compile Include="EnvironmentService.cs" />
|
<Compile Include="EnvironmentService.cs" />
|
||||||
<Compile Include="Images\ImageRequest.cs" />
|
<Compile Include="Images\ImageRequest.cs" />
|
||||||
<Compile Include="Images\ImageService.cs" />
|
<Compile Include="Images\ImageService.cs" />
|
||||||
|
@ -104,7 +104,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class PackageService
|
/// Class PackageService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PackageService : BaseRestService
|
public class PackageService : BaseApiService
|
||||||
{
|
{
|
||||||
private readonly IInstallationManager _installationManager;
|
private readonly IInstallationManager _installationManager;
|
||||||
private readonly IApplicationHost _appHost;
|
private readonly IApplicationHost _appHost;
|
||||||
|
@ -21,7 +21,7 @@ namespace MediaBrowser.Api.Playback
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class BaseStreamingService
|
/// Class BaseStreamingService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseStreamingService : BaseRestService
|
public abstract class BaseStreamingService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the application paths.
|
/// Gets or sets the application paths.
|
||||||
|
@ -126,7 +126,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class PluginsService
|
/// Class PluginsService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PluginService : BaseRestService
|
public class PluginService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _json serializer
|
/// The _json serializer
|
||||||
|
@ -83,7 +83,7 @@ namespace MediaBrowser.Api.ScheduledTasks
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class ScheduledTasksService
|
/// Class ScheduledTasksService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ScheduledTaskService : BaseRestService
|
public class ScheduledTaskService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the task manager.
|
/// Gets or sets the task manager.
|
||||||
|
@ -4,7 +4,6 @@ using MediaBrowser.Controller.Configuration;
|
|||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using MediaBrowser.Model.System;
|
using MediaBrowser.Model.System;
|
||||||
using MediaBrowser.Server.Implementations.HttpServer;
|
|
||||||
using ServiceStack.ServiceHost;
|
using ServiceStack.ServiceHost;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -59,7 +58,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class SystemInfoService
|
/// Class SystemInfoService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SystemService : BaseRestService
|
public class SystemService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _json serializer
|
/// The _json serializer
|
||||||
|
@ -16,7 +16,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
/// Class BaseItemsByNameService
|
/// Class BaseItemsByNameService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TItemType">The type of the T item type.</typeparam>
|
/// <typeparam name="TItemType">The type of the T item type.</typeparam>
|
||||||
public abstract class BaseItemsByNameService<TItemType> : BaseRestService
|
public abstract class BaseItemsByNameService<TItemType> : BaseApiService
|
||||||
where TItemType : BaseItem
|
where TItemType : BaseItem
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -112,7 +112,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class ItemsService
|
/// Class ItemsService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ItemsService : BaseRestService
|
public class ItemsService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _user manager
|
/// The _user manager
|
||||||
|
@ -6,6 +6,7 @@ using MediaBrowser.Model.Dto;
|
|||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Server.Implementations.HttpServer;
|
using MediaBrowser.Server.Implementations.HttpServer;
|
||||||
|
using MediaBrowser.Server.Implementations.Library;
|
||||||
using ServiceStack.ServiceHost;
|
using ServiceStack.ServiceHost;
|
||||||
using ServiceStack.Text.Controller;
|
using ServiceStack.Text.Controller;
|
||||||
using System;
|
using System;
|
||||||
@ -347,7 +348,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class UserLibraryService
|
/// Class UserLibraryService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UserLibraryService : BaseRestService
|
public class UserLibraryService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _user manager
|
/// The _user manager
|
||||||
@ -592,7 +593,16 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
|
var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
|
||||||
|
|
||||||
_userManager.OnPlaybackStart(user, item, ClientType.Other, string.Empty);
|
var auth = RequestFilterAttribute.GetAuthorization(Request);
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
{
|
||||||
|
ClientType clientType;
|
||||||
|
|
||||||
|
Enum.TryParse(auth["Client"] ?? string.Empty, out clientType);
|
||||||
|
|
||||||
|
_userManager.OnPlaybackStart(user, item, clientType, auth["DeviceId"], auth["Device"] ?? string.Empty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -605,10 +615,19 @@ 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 task = _userManager.OnPlaybackProgress(user, item, request.PositionTicks, ClientType.Other, string.Empty);
|
var auth = RequestFilterAttribute.GetAuthorization(Request);
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
{
|
||||||
|
ClientType clientType;
|
||||||
|
|
||||||
|
Enum.TryParse(auth["Client"] ?? string.Empty, out clientType);
|
||||||
|
|
||||||
|
var task = _userManager.OnPlaybackProgress(user, item, request.PositionTicks, clientType, auth["DeviceId"], auth["Device"] ?? string.Empty);
|
||||||
|
|
||||||
Task.WaitAll(task);
|
Task.WaitAll(task);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Posts the specified request.
|
/// Posts the specified request.
|
||||||
@ -620,10 +639,19 @@ 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 task = _userManager.OnPlaybackStopped(user, item, request.PositionTicks, ClientType.Other, string.Empty);
|
var auth = RequestFilterAttribute.GetAuthorization(Request);
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
{
|
||||||
|
ClientType clientType;
|
||||||
|
|
||||||
|
Enum.TryParse(auth["Client"] ?? string.Empty, out clientType);
|
||||||
|
|
||||||
|
var task = _userManager.OnPlaybackStopped(user, item, request.PositionTicks, clientType, auth["DeviceId"], auth["Device"] ?? string.Empty);
|
||||||
|
|
||||||
Task.WaitAll(task);
|
Task.WaitAll(task);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes the specified request.
|
/// Deletes the specified request.
|
||||||
|
@ -126,7 +126,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class UsersService
|
/// Class UsersService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UserService : BaseRestService
|
public class UserService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _XML serializer
|
/// The _XML serializer
|
||||||
|
@ -25,7 +25,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class WeatherService
|
/// Class WeatherService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WeatherService : BaseRestService
|
public class WeatherService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the specified request.
|
/// Gets the specified request.
|
||||||
|
@ -69,10 +69,11 @@ namespace MediaBrowser.Controller.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
/// <param name="clientType">Type of the client.</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="deviceName">Name of the device.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException">user</exception>
|
/// <exception cref="System.ArgumentNullException">user</exception>
|
||||||
Task LogUserActivity(User user, ClientType clientType, string deviceName);
|
Task LogUserActivity(User user, ClientType clientType, string deviceId, string deviceName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refreshes metadata for each user
|
/// Refreshes metadata for each user
|
||||||
@ -124,9 +125,10 @@ namespace MediaBrowser.Controller.Library
|
|||||||
/// <param name="user">The user.</param>
|
/// <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="clientType">Type of the client.</param>
|
||||||
|
/// <param name="deviceId">The device id.</param>
|
||||||
/// <param name="deviceName">Name of the device.</param>
|
/// <param name="deviceName">Name of the device.</param>
|
||||||
/// <exception cref="System.ArgumentNullException"></exception>
|
/// <exception cref="System.ArgumentNullException"></exception>
|
||||||
void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceName);
|
void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceId, string deviceName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to report playback progress for an item
|
/// Used to report playback progress for an item
|
||||||
@ -135,10 +137,11 @@ namespace MediaBrowser.Controller.Library
|
|||||||
/// <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="clientType">Type of the client.</param>
|
||||||
|
/// <param name="deviceId">The device id.</param>
|
||||||
/// <param name="deviceName">Name of the device.</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, ClientType clientType, string deviceName);
|
Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceId, string deviceName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to report that playback has ended for an item
|
/// Used to report that playback has ended for an item
|
||||||
@ -147,10 +150,11 @@ namespace MediaBrowser.Controller.Library
|
|||||||
/// <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="clientType">Type of the client.</param>
|
||||||
|
/// <param name="deviceId">The device id.</param>
|
||||||
/// <param name="deviceName">Name of the device.</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, ClientType clientType, string deviceName);
|
Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceId, string deviceName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves user data for an item
|
/// Saves user data for an item
|
||||||
|
@ -51,5 +51,12 @@ namespace MediaBrowser.Model.Connectivity
|
|||||||
/// <value>The now playing position ticks.</value>
|
/// <value>The now playing position ticks.</value>
|
||||||
[ProtoMember(6)]
|
[ProtoMember(6)]
|
||||||
public long? NowPlayingPositionTicks { get; set; }
|
public long? NowPlayingPositionTicks { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the device id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The device id.</value>
|
||||||
|
[ProtoMember(7)]
|
||||||
|
public string DeviceId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
/// The dashboard
|
/// The dashboard
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dashboard,
|
Dashboard,
|
||||||
|
/// <summary>
|
||||||
|
/// The dlna
|
||||||
|
/// </summary>
|
||||||
Dlna,
|
Dlna,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ios
|
/// The ios
|
||||||
|
@ -122,5 +122,11 @@ namespace MediaBrowser.Model.Querying
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The image types.</value>
|
/// <value>The image types.</value>
|
||||||
public ImageType[] ImageTypes { get; set; }
|
public ImageType[] ImageTypes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the ids, which are specific items to retrieve
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The ids.</value>
|
||||||
|
public string[] Ids { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,10 +222,11 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
/// <param name="clientType">Type of the client.</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="deviceName">Name of the device.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException">user</exception>
|
/// <exception cref="System.ArgumentNullException">user</exception>
|
||||||
public Task LogUserActivity(User user, ClientType clientType, string deviceName)
|
public Task LogUserActivity(User user, ClientType clientType, string deviceId, string deviceName)
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
@ -236,7 +237,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
|
|
||||||
user.LastActivityDate = activityDate;
|
user.LastActivityDate = activityDate;
|
||||||
|
|
||||||
LogConnection(user.Id, clientType, deviceName, activityDate);
|
LogConnection(user.Id, clientType, deviceId, deviceName, activityDate);
|
||||||
|
|
||||||
// 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 Kernel.UserRepository.SaveUser(user, CancellationToken.None);
|
return Kernel.UserRepository.SaveUser(user, CancellationToken.None);
|
||||||
@ -247,15 +248,17 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
/// <param name="clientType">Type of the client.</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="deviceName">Name of the device.</param>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <param name="currentPositionTicks">The current position ticks.</param>
|
/// <param name="currentPositionTicks">The current position ticks.</param>
|
||||||
private void UpdateNowPlayingItemId(User user, ClientType clientType, string deviceName, BaseItem item, long? currentPositionTicks = null)
|
private void UpdateNowPlayingItemId(User user, ClientType clientType, string deviceId, string deviceName, BaseItem item, long? currentPositionTicks = null)
|
||||||
{
|
{
|
||||||
var conn = GetConnection(user.Id, clientType, deviceName);
|
var conn = GetConnection(user.Id, clientType, deviceId, deviceName);
|
||||||
|
|
||||||
conn.NowPlayingPositionTicks = currentPositionTicks;
|
conn.NowPlayingPositionTicks = currentPositionTicks;
|
||||||
conn.NowPlayingItem = DtoBuilder.GetBaseItemInfo(item);
|
conn.NowPlayingItem = DtoBuilder.GetBaseItemInfo(item);
|
||||||
|
conn.LastActivityDate = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -263,11 +266,12 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
/// <param name="clientType">Type of the client.</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="deviceName">Name of the device.</param>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
private void RemoveNowPlayingItemId(User user, ClientType clientType, string deviceName, BaseItem item)
|
private void RemoveNowPlayingItemId(User user, ClientType clientType, string deviceId, string deviceName, BaseItem item)
|
||||||
{
|
{
|
||||||
var conn = GetConnection(user.Id, clientType, deviceName);
|
var conn = GetConnection(user.Id, clientType, deviceId, deviceName);
|
||||||
|
|
||||||
if (conn.NowPlayingItem != null && conn.NowPlayingItem.Id.Equals(item.Id.ToString()))
|
if (conn.NowPlayingItem != null && conn.NowPlayingItem.Id.Equals(item.Id.ToString()))
|
||||||
{
|
{
|
||||||
@ -281,11 +285,12 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userId">The user id.</param>
|
/// <param name="userId">The user id.</param>
|
||||||
/// <param name="clientType">Type of the client.</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="deviceName">Name of the device.</param>
|
||||||
/// <param name="lastActivityDate">The last activity date.</param>
|
/// <param name="lastActivityDate">The last activity date.</param>
|
||||||
private void LogConnection(Guid userId, ClientType clientType, string deviceName, DateTime lastActivityDate)
|
private void LogConnection(Guid userId, ClientType clientType, string deviceId, string deviceName, DateTime lastActivityDate)
|
||||||
{
|
{
|
||||||
GetConnection(userId, clientType, deviceName).LastActivityDate = lastActivityDate;
|
GetConnection(userId, clientType, deviceId, deviceName).LastActivityDate = lastActivityDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -293,11 +298,12 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userId">The user id.</param>
|
/// <param name="userId">The user id.</param>
|
||||||
/// <param name="clientType">Type of the client.</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="deviceName">Name of the device.</param>
|
||||||
/// <returns>ClientConnectionInfo.</returns>
|
/// <returns>ClientConnectionInfo.</returns>
|
||||||
private ClientConnectionInfo GetConnection(Guid userId, ClientType clientType, string deviceName)
|
private ClientConnectionInfo GetConnection(Guid userId, ClientType clientType, string deviceId, string deviceName)
|
||||||
{
|
{
|
||||||
var conn = _activeConnections.FirstOrDefault(c => c.UserId == userId && c.ClientType == clientType && string.Equals(deviceName, c.DeviceName, StringComparison.OrdinalIgnoreCase));
|
var conn = _activeConnections.FirstOrDefault(c => c.UserId == userId && c.ClientType == clientType && string.Equals(deviceId, c.DeviceId));
|
||||||
|
|
||||||
if (conn == null)
|
if (conn == null)
|
||||||
{
|
{
|
||||||
@ -305,7 +311,8 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
UserId = userId,
|
UserId = userId,
|
||||||
ClientType = clientType,
|
ClientType = clientType,
|
||||||
DeviceName = deviceName
|
DeviceName = deviceName,
|
||||||
|
DeviceId = deviceId
|
||||||
};
|
};
|
||||||
|
|
||||||
_activeConnections.Add(conn);
|
_activeConnections.Add(conn);
|
||||||
@ -524,9 +531,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
/// <param name="user">The user.</param>
|
/// <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="clientType">Type of the client.</param>
|
||||||
|
/// <param name="deviceId">The device id.</param>
|
||||||
/// <param name="deviceName">Name of the device.</param>
|
/// <param name="deviceName">Name of the device.</param>
|
||||||
/// <exception cref="System.ArgumentNullException"></exception>
|
/// <exception cref="System.ArgumentNullException"></exception>
|
||||||
public void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceName)
|
public void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceId, string deviceName)
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
@ -537,7 +545,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
throw new ArgumentNullException();
|
throw new ArgumentNullException();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateNowPlayingItemId(user, clientType, deviceName, item);
|
UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item);
|
||||||
|
|
||||||
// Nothing to save here
|
// Nothing to save here
|
||||||
// Fire events to inform plugins
|
// Fire events to inform plugins
|
||||||
@ -555,10 +563,11 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
/// <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="clientType">Type of the client.</param>
|
||||||
|
/// <param name="deviceId">The device id.</param>
|
||||||
/// <param name="deviceName">Name of the device.</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>
|
||||||
public async Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName)
|
public async Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceId, string deviceName)
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
@ -569,7 +578,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
throw new ArgumentNullException();
|
throw new ArgumentNullException();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateNowPlayingItemId(user, clientType, deviceName, item, positionTicks);
|
UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, positionTicks);
|
||||||
|
|
||||||
if (positionTicks.HasValue)
|
if (positionTicks.HasValue)
|
||||||
{
|
{
|
||||||
@ -594,10 +603,11 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
/// <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="clientType">Type of the client.</param>
|
||||||
|
/// <param name="deviceId">The device id.</param>
|
||||||
/// <param name="deviceName">Name of the device.</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>
|
||||||
public async Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName)
|
public async Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceId, string deviceName)
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
@ -608,7 +618,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
throw new ArgumentNullException();
|
throw new ArgumentNullException();
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveNowPlayingItemId(user, clientType, deviceName, item);
|
RemoveNowPlayingItemId(user, clientType, deviceId, deviceName, item);
|
||||||
|
|
||||||
var data = item.GetUserData(user, true);
|
var data = item.GetUserData(user, true);
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ var ApiClient = {
|
|||||||
|
|
||||||
serverPortNumber: 8096,
|
serverPortNumber: 8096,
|
||||||
|
|
||||||
|
currentUserId: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detects the hostname and port of MB server based on the current url
|
* Detects the hostname and port of MB server based on the current url
|
||||||
*/
|
*/
|
||||||
@ -36,14 +38,12 @@ var ApiClient = {
|
|||||||
throw new Error("Url name cannot be empty");
|
throw new Error("Url name cannot be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
params = params || {};
|
|
||||||
|
|
||||||
var url = ApiClient.serverProtocol + "//" + ApiClient.serverHostName + ":" + ApiClient.serverPortNumber + "/mediabrowser/" + name;
|
var url = ApiClient.serverProtocol + "//" + ApiClient.serverHostName + ":" + ApiClient.serverPortNumber + "/mediabrowser/" + name;
|
||||||
|
|
||||||
if (params) {
|
if (params) {
|
||||||
url += "?" + $.param(params);
|
url += "?" + $.param(params);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -77,6 +77,10 @@ var ApiClient = {
|
|||||||
return "Web Browser";
|
return "Web Browser";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getDeviceId: function() {
|
||||||
|
return SHA1(navigator.userAgent + (navigator.cpuClass || ""));
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a custom api url based on a handler name and query string parameters
|
* Creates a custom api url based on a handler name and query string parameters
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
@ -89,16 +93,14 @@ var ApiClient = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
params = params || {};
|
params = params || {};
|
||||||
params.client = "Dashboard";
|
|
||||||
params.device = ApiClient.getDeviceName();
|
|
||||||
params.format = "json";
|
params.format = "json";
|
||||||
|
|
||||||
var url = ApiClient.serverProtocol + "//" + ApiClient.serverHostName + ":" + ApiClient.serverPortNumber + "/mediabrowser/" + name;
|
var url = ApiClient.serverProtocol + "//" + ApiClient.serverHostName + ":" + ApiClient.serverPortNumber + "/mediabrowser/" + name;
|
||||||
|
|
||||||
if (params) {
|
if (params) {
|
||||||
url += "?" + $.param(params);
|
url += "?" + $.param(params);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1380,3 +1382,12 @@ var ApiClient = {
|
|||||||
|
|
||||||
// Do this initially. The consumer can always override later
|
// Do this initially. The consumer can always override later
|
||||||
ApiClient.inferServerFromUrl();
|
ApiClient.inferServerFromUrl();
|
||||||
|
|
||||||
|
$(document).ajaxSend(function (event, jqXHR) {
|
||||||
|
|
||||||
|
if (ApiClient.currentUserId) {
|
||||||
|
|
||||||
|
var auth = 'MediaBrowser UserId="' + ApiClient.currentUserId + '", Client="Dashboard", Device="' + ApiClient.getDeviceName() + '", DeviceId="' + ApiClient.getDeviceName() + '"';
|
||||||
|
jqXHR.setRequestHeader("Authorization", auth);
|
||||||
|
}
|
||||||
|
});
|
@ -81,12 +81,14 @@ var Dashboard = {
|
|||||||
|
|
||||||
setCurrentUser: function (userId) {
|
setCurrentUser: function (userId) {
|
||||||
localStorage.setItem("userId", userId);
|
localStorage.setItem("userId", userId);
|
||||||
|
ApiClient.currentUserId = userId;
|
||||||
Dashboard.getUserPromise = null;
|
Dashboard.getUserPromise = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
logout: function () {
|
logout: function () {
|
||||||
localStorage.removeItem("userId");
|
localStorage.removeItem("userId");
|
||||||
Dashboard.getUserPromise = null;
|
Dashboard.getUserPromise = null;
|
||||||
|
ApiClient.currentUserId = null;
|
||||||
window.location = "login.html";
|
window.location = "login.html";
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1113,6 +1115,13 @@ var Dashboard = {
|
|||||||
tag: item.PrimaryImageTag,
|
tag: item.PrimaryImageTag,
|
||||||
type: "Primary"
|
type: "Primary"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!item.Id || data.icon.indexOf("undefined") != -1) {
|
||||||
|
alert("bad image url: " + JSON.stringify(item));
|
||||||
|
console.log("bad image url: " + JSON.stringify(item));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WebNotifications.show(data);
|
WebNotifications.show(data);
|
||||||
@ -1200,9 +1209,11 @@ $(document).on('pagebeforeshow', ".page", function () {
|
|||||||
}).on('pageinit', ".page", function () {
|
}).on('pageinit', ".page", function () {
|
||||||
|
|
||||||
var page = $(this);
|
var page = $(this);
|
||||||
var hasLogin = Dashboard.getCurrentUserId();
|
|
||||||
|
|
||||||
if (!hasLogin) {
|
var userId = Dashboard.getCurrentUserId();
|
||||||
|
ApiClient.currentUserId = userId;
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
|
||||||
if (this.id !== "loginPage" && !page.hasClass('wizardPage')) {
|
if (this.id !== "loginPage" && !page.hasClass('wizardPage')) {
|
||||||
|
|
||||||
|
@ -221,4 +221,7 @@ Global
|
|||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(Performance) = preSolution
|
||||||
|
HasPerformanceSessions = true
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common.Internal</id>
|
<id>MediaBrowser.Common.Internal</id>
|
||||||
<version>3.0.47</version>
|
<version>3.0.48</version>
|
||||||
<title>MediaBrowser.Common.Internal</title>
|
<title>MediaBrowser.Common.Internal</title>
|
||||||
<authors>Luke</authors>
|
<authors>Luke</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<description>Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption.</description>
|
<description>Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.47" />
|
<dependency id="MediaBrowser.Common" version="3.0.48" />
|
||||||
<dependency id="NLog" version="2.0.0.2000" />
|
<dependency id="NLog" version="2.0.0.2000" />
|
||||||
<dependency id="ServiceStack.Text" version="3.9.38" />
|
<dependency id="ServiceStack.Text" version="3.9.38" />
|
||||||
<dependency id="protobuf-net" version="2.0.0.621" />
|
<dependency id="protobuf-net" version="2.0.0.621" />
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common</id>
|
<id>MediaBrowser.Common</id>
|
||||||
<version>3.0.47</version>
|
<version>3.0.48</version>
|
||||||
<title>MediaBrowser.Common</title>
|
<title>MediaBrowser.Common</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Server.Core</id>
|
<id>MediaBrowser.Server.Core</id>
|
||||||
<version>3.0.47</version>
|
<version>3.0.48</version>
|
||||||
<title>Media Browser.Server.Core</title>
|
<title>Media Browser.Server.Core</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.47" />
|
<dependency id="MediaBrowser.Common" version="3.0.48" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user