mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	support more kinds of remote control besides web socket
This commit is contained in:
		
							parent
							
								
									04319900f9
								
							
						
					
					
						commit
						c61cc4a304
					
				@ -325,49 +325,11 @@ namespace MediaBrowser.Api
 | 
			
		||||
        /// <param name="request">The request.</param>
 | 
			
		||||
        public void Post(SendSystemCommand request)
 | 
			
		||||
        {
 | 
			
		||||
            var task = SendSystemCommand(request);
 | 
			
		||||
            var task = _sessionManager.SendSystemCommand(request.Id, request.Command, CancellationToken.None);
 | 
			
		||||
 | 
			
		||||
            Task.WaitAll(task);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task SendSystemCommand(SendSystemCommand 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<string>
 | 
			
		||||
                    {
 | 
			
		||||
                        MessageType = "SystemCommand",
 | 
			
		||||
                        Data = request.Command.ToString()
 | 
			
		||||
 | 
			
		||||
                    }, 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>
 | 
			
		||||
        /// Posts the specified request.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
 | 
			
		||||
@ -165,6 +165,7 @@
 | 
			
		||||
    <Compile Include="Kernel.cs" />
 | 
			
		||||
    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
			
		||||
    <Compile Include="Providers\BaseMetadataProvider.cs" />
 | 
			
		||||
    <Compile Include="Session\ISessionRemoteController.cs" />
 | 
			
		||||
    <Compile Include="Session\PlaybackInfo.cs" />
 | 
			
		||||
    <Compile Include="Session\SessionInfo.cs" />
 | 
			
		||||
    <Compile Include="Sorting\IBaseItemComparer.cs" />
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,9 @@
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Model.Session;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace MediaBrowser.Controller.Session
 | 
			
		||||
@ -11,6 +13,12 @@ namespace MediaBrowser.Controller.Session
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public interface ISessionManager
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Adds the parts.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="remoteControllers">The remote controllers.</param>
 | 
			
		||||
        void AddParts(IEnumerable<ISessionRemoteController> remoteControllers);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Occurs when [playback start].
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@ -72,5 +80,14 @@ namespace MediaBrowser.Controller.Session
 | 
			
		||||
        /// <returns>Task.</returns>
 | 
			
		||||
        /// <exception cref="System.ArgumentNullException"></exception>
 | 
			
		||||
        Task OnPlaybackStopped(BaseItem item, long? positionTicks, Guid sessionId);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Sends the system command.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="sessionId">The session id.</param>
 | 
			
		||||
        /// <param name="command">The command.</param>
 | 
			
		||||
        /// <param name="cancellationToken">The cancellation token.</param>
 | 
			
		||||
        /// <returns>Task.</returns>
 | 
			
		||||
        Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								MediaBrowser.Controller/Session/ISessionRemoteController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								MediaBrowser.Controller/Session/ISessionRemoteController.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
using MediaBrowser.Model.Session;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace MediaBrowser.Controller.Session
 | 
			
		||||
{
 | 
			
		||||
    public interface ISessionRemoteController
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Supportses the specified session.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="session">The session.</param>
 | 
			
		||||
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
 | 
			
		||||
        bool Supports(SessionInfo session);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Sends the system command.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="session">The session.</param>
 | 
			
		||||
        /// <param name="command">The command.</param>
 | 
			
		||||
        /// <param name="cancellationToken">The cancellation token.</param>
 | 
			
		||||
        /// <returns>Task.</returns>
 | 
			
		||||
        Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -183,6 +183,7 @@
 | 
			
		||||
      <SubType>Code</SubType>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <Compile Include="Session\SessionWebSocketListener.cs" />
 | 
			
		||||
    <Compile Include="Session\WebSocketController.cs" />
 | 
			
		||||
    <Compile Include="Sorting\AlbumArtistComparer.cs" />
 | 
			
		||||
    <Compile Include="Sorting\AlbumComparer.cs" />
 | 
			
		||||
    <Compile Include="Sorting\AlbumCountComparer.cs" />
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using MediaBrowser.Common.Events;
 | 
			
		||||
using MediaBrowser.Common.Extensions;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Controller.Entities;
 | 
			
		||||
using MediaBrowser.Controller.Entities.Audio;
 | 
			
		||||
@ -6,6 +7,7 @@ using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.Persistence;
 | 
			
		||||
using MediaBrowser.Controller.Session;
 | 
			
		||||
using MediaBrowser.Model.Logging;
 | 
			
		||||
using MediaBrowser.Model.Session;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
@ -75,6 +77,12 @@ namespace MediaBrowser.Server.Implementations.Session
 | 
			
		||||
            _userRepository = userRepository;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private List<ISessionRemoteController> _remoteControllers;
 | 
			
		||||
        public void AddParts(IEnumerable<ISessionRemoteController> remoteControllers)
 | 
			
		||||
        {
 | 
			
		||||
            _remoteControllers = remoteControllers.ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets all connections.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@ -122,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.Session
 | 
			
		||||
            var activityDate = DateTime.UtcNow;
 | 
			
		||||
 | 
			
		||||
            var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, user);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            session.LastActivityDate = activityDate;
 | 
			
		||||
 | 
			
		||||
            if (user == null)
 | 
			
		||||
@ -233,7 +241,7 @@ namespace MediaBrowser.Server.Implementations.Session
 | 
			
		||||
            var key = item.GetUserDataKey();
 | 
			
		||||
 | 
			
		||||
            var user = session.User;
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            var data = _userDataRepository.GetUserData(user.Id, key);
 | 
			
		||||
 | 
			
		||||
            data.PlayCount++;
 | 
			
		||||
@ -321,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.Session
 | 
			
		||||
            {
 | 
			
		||||
                throw new ArgumentOutOfRangeException("positionTicks");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            var session = Sessions.First(i => i.Id.Equals(sessionId));
 | 
			
		||||
 | 
			
		||||
            RemoveNowPlayingItem(session, item);
 | 
			
		||||
@ -329,7 +337,7 @@ namespace MediaBrowser.Server.Implementations.Session
 | 
			
		||||
            var key = item.GetUserDataKey();
 | 
			
		||||
 | 
			
		||||
            var user = session.User;
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            var data = _userDataRepository.GetUserData(user.Id, key);
 | 
			
		||||
 | 
			
		||||
            if (positionTicks.HasValue)
 | 
			
		||||
@ -408,5 +416,54 @@ namespace MediaBrowser.Server.Implementations.Session
 | 
			
		||||
 | 
			
		||||
            data.PlaybackPositionTicks = positionTicks;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the session for remote control.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="sessionId">The session id.</param>
 | 
			
		||||
        /// <returns>SessionInfo.</returns>
 | 
			
		||||
        /// <exception cref="ResourceNotFoundException"></exception>
 | 
			
		||||
        private SessionInfo GetSessionForRemoteControl(Guid sessionId)
 | 
			
		||||
        {
 | 
			
		||||
            var session = Sessions.First(i => i.Id.Equals(sessionId));
 | 
			
		||||
 | 
			
		||||
            if (session == null)
 | 
			
		||||
            {
 | 
			
		||||
                throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!session.SupportsRemoteControl)
 | 
			
		||||
            {
 | 
			
		||||
                throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id));
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return session;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the controllers.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="session">The session.</param>
 | 
			
		||||
        /// <returns>IEnumerable{ISessionRemoteController}.</returns>
 | 
			
		||||
        private IEnumerable<ISessionRemoteController> GetControllers(SessionInfo session)
 | 
			
		||||
        {
 | 
			
		||||
            return _remoteControllers.Where(i => i.Supports(session));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Sends the system command.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="sessionId">The session id.</param>
 | 
			
		||||
        /// <param name="command">The command.</param>
 | 
			
		||||
        /// <param name="cancellationToken">The cancellation token.</param>
 | 
			
		||||
        /// <returns>Task.</returns>
 | 
			
		||||
        public Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken)
 | 
			
		||||
        {
 | 
			
		||||
            var session = GetSessionForRemoteControl(sessionId);
 | 
			
		||||
 | 
			
		||||
            var tasks = GetControllers(session).Select(i => i.SendSystemCommand(session, command, cancellationToken));
 | 
			
		||||
 | 
			
		||||
            return Task.WhenAll(tasks);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,52 @@
 | 
			
		||||
using MediaBrowser.Controller.Session;
 | 
			
		||||
using MediaBrowser.Model.Logging;
 | 
			
		||||
using MediaBrowser.Model.Net;
 | 
			
		||||
using MediaBrowser.Model.Session;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace MediaBrowser.Server.Implementations.Session
 | 
			
		||||
{
 | 
			
		||||
    public class WebSocketController : ISessionRemoteController
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger _logger;
 | 
			
		||||
 | 
			
		||||
        public WebSocketController(ILogger logger)
 | 
			
		||||
        {
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool Supports(SessionInfo session)
 | 
			
		||||
        {
 | 
			
		||||
            return session.WebSockets.Any(i => i.State == WebSocketState.Open);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken)
 | 
			
		||||
        {
 | 
			
		||||
            var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open);
 | 
			
		||||
 | 
			
		||||
            if (socket != null)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await socket.SendAsync(new WebSocketMessage<string>
 | 
			
		||||
                    {
 | 
			
		||||
                        MessageType = "SystemCommand",
 | 
			
		||||
                        Data = command.ToString()
 | 
			
		||||
 | 
			
		||||
                    }, cancellationToken).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.");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -161,6 +161,7 @@ namespace MediaBrowser.ServerApplication
 | 
			
		||||
        private IMediaEncoder MediaEncoder { get; set; }
 | 
			
		||||
 | 
			
		||||
        private IIsoManager IsoManager { get; set; }
 | 
			
		||||
        private ISessionManager SessionManager { get; set; }
 | 
			
		||||
 | 
			
		||||
        private ILocalizationManager LocalizationManager { get; set; }
 | 
			
		||||
 | 
			
		||||
@ -286,8 +287,8 @@ namespace MediaBrowser.ServerApplication
 | 
			
		||||
 | 
			
		||||
            RegisterSingleInstance<ILibrarySearchEngine>(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager));
 | 
			
		||||
 | 
			
		||||
            var clientConnectionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository);
 | 
			
		||||
            RegisterSingleInstance<ISessionManager>(clientConnectionManager);
 | 
			
		||||
            SessionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository);
 | 
			
		||||
            RegisterSingleInstance<ISessionManager>(SessionManager);
 | 
			
		||||
 | 
			
		||||
            HttpServer = await _httpServerCreationTask.ConfigureAwait(false);
 | 
			
		||||
            RegisterSingleInstance(HttpServer, false);
 | 
			
		||||
@ -477,6 +478,8 @@ namespace MediaBrowser.ServerApplication
 | 
			
		||||
 | 
			
		||||
            IsoManager.AddParts(GetExports<IIsoMounter>());
 | 
			
		||||
 | 
			
		||||
            SessionManager.AddParts(GetExports<ISessionRemoteController>());
 | 
			
		||||
            
 | 
			
		||||
            ImageProcessor.AddParts(GetExports<IImageEnhancer>());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user