< Summary - Jellyfin

Information
Class: MediaBrowser.Controller.Session.SessionInfo
Assembly: MediaBrowser.Controller
File(s): /srv/git/jellyfin/MediaBrowser.Controller/Session/SessionInfo.cs
Line coverage
36%
Covered lines: 25
Uncovered lines: 43
Coverable lines: 68
Total lines: 400
Line coverage: 36.7%
Branch coverage
26%
Covered branches: 11
Total branches: 42
Branch coverage: 26.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_PlayableMediaTypes()50%2.15266.66%
get_IsActive()33.33%8.83657.14%
get_SupportsMediaControl()37.5%31.33828.57%
get_SupportsRemoteControl()37.5%31.33828.57%
get_SupportedCommands()50%22100%
EnsureController(...)0%2040%
AddController(...)100%210%
ContainsUser(...)0%4260%
StartAutomaticProgress(...)0%2040%
StopAutomaticProgress()50%2.09271.42%

File(s)

/srv/git/jellyfin/MediaBrowser.Controller/Session/SessionInfo.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CS1591
 4
 5using System;
 6using System.Collections.Generic;
 7using System.Linq;
 8using System.Text.Json.Serialization;
 9using System.Threading;
 10using System.Threading.Tasks;
 11using Jellyfin.Data.Enums;
 12using MediaBrowser.Controller.Entities;
 13using MediaBrowser.Model.Dto;
 14using MediaBrowser.Model.Session;
 15using Microsoft.Extensions.Logging;
 16
 17namespace MediaBrowser.Controller.Session
 18{
 19    /// <summary>
 20    /// Class SessionInfo.
 21    /// </summary>
 22    public sealed class SessionInfo : IAsyncDisposable
 23    {
 24        // 1 second
 25        private const long ProgressIncrement = 10000000;
 26
 27        private readonly ISessionManager _sessionManager;
 28        private readonly ILogger _logger;
 29
 1730        private readonly object _progressLock = new object();
 31        private Timer _progressTimer;
 32        private PlaybackProgressInfo _lastProgressInfo;
 33
 34        private bool _disposed = false;
 35
 36        public SessionInfo(ISessionManager sessionManager, ILogger logger)
 37        {
 1738            _sessionManager = sessionManager;
 1739            _logger = logger;
 40
 1741            AdditionalUsers = Array.Empty<SessionUserInfo>();
 1742            PlayState = new PlayerStateInfo();
 1743            SessionControllers = Array.Empty<ISessionController>();
 1744            NowPlayingQueue = Array.Empty<QueueItem>();
 1745            NowPlayingQueueFullItems = Array.Empty<BaseItemDto>();
 1746        }
 47
 48        public PlayerStateInfo PlayState { get; set; }
 49
 50        public SessionUserInfo[] AdditionalUsers { get; set; }
 51
 52        public ClientCapabilities Capabilities { get; set; }
 53
 54        /// <summary>
 55        /// Gets or sets the remote end point.
 56        /// </summary>
 57        /// <value>The remote end point.</value>
 58        public string RemoteEndPoint { get; set; }
 59
 60        /// <summary>
 61        /// Gets the playable media types.
 62        /// </summary>
 63        /// <value>The playable media types.</value>
 64        public IReadOnlyList<MediaType> PlayableMediaTypes
 65        {
 66            get
 67            {
 1668                if (Capabilities is null)
 69                {
 070                    return Array.Empty<MediaType>();
 71                }
 72
 1673                return Capabilities.PlayableMediaTypes;
 74            }
 75        }
 76
 77        /// <summary>
 78        /// Gets or sets the id.
 79        /// </summary>
 80        /// <value>The id.</value>
 81        public string Id { get; set; }
 82
 83        /// <summary>
 84        /// Gets or sets the user id.
 85        /// </summary>
 86        /// <value>The user id.</value>
 87        public Guid UserId { get; set; }
 88
 89        /// <summary>
 90        /// Gets or sets the username.
 91        /// </summary>
 92        /// <value>The username.</value>
 93        public string UserName { get; set; }
 94
 95        /// <summary>
 96        /// Gets or sets the type of the client.
 97        /// </summary>
 98        /// <value>The type of the client.</value>
 99        public string Client { get; set; }
 100
 101        /// <summary>
 102        /// Gets or sets the last activity date.
 103        /// </summary>
 104        /// <value>The last activity date.</value>
 105        public DateTime LastActivityDate { get; set; }
 106
 107        /// <summary>
 108        /// Gets or sets the last playback check in.
 109        /// </summary>
 110        /// <value>The last playback check in.</value>
 111        public DateTime LastPlaybackCheckIn { get; set; }
 112
 113        /// <summary>
 114        /// Gets or sets the last paused date.
 115        /// </summary>
 116        /// <value>The last paused date.</value>
 117        public DateTime? LastPausedDate { get; set; }
 118
 119        /// <summary>
 120        /// Gets or sets the name of the device.
 121        /// </summary>
 122        /// <value>The name of the device.</value>
 123        public string DeviceName { get; set; }
 124
 125        /// <summary>
 126        /// Gets or sets the type of the device.
 127        /// </summary>
 128        /// <value>The type of the device.</value>
 129        public string DeviceType { get; set; }
 130
 131        /// <summary>
 132        /// Gets or sets the now playing item.
 133        /// </summary>
 134        /// <value>The now playing item.</value>
 135        public BaseItemDto NowPlayingItem { get; set; }
 136
 137        [JsonIgnore]
 138        public BaseItem FullNowPlayingItem { get; set; }
 139
 140        public BaseItemDto NowViewingItem { get; set; }
 141
 142        /// <summary>
 143        /// Gets or sets the device id.
 144        /// </summary>
 145        /// <value>The device id.</value>
 146        public string DeviceId { get; set; }
 147
 148        /// <summary>
 149        /// Gets or sets the application version.
 150        /// </summary>
 151        /// <value>The application version.</value>
 152        public string ApplicationVersion { get; set; }
 153
 154        /// <summary>
 155        /// Gets or sets the session controller.
 156        /// </summary>
 157        /// <value>The session controller.</value>
 158        [JsonIgnore]
 159        public ISessionController[] SessionControllers { get; set; }
 160
 161        public TranscodingInfo TranscodingInfo { get; set; }
 162
 163        /// <summary>
 164        /// Gets a value indicating whether this instance is active.
 165        /// </summary>
 166        /// <value><c>true</c> if this instance is active; otherwise, <c>false</c>.</value>
 167        public bool IsActive
 168        {
 169            get
 170            {
 16171                var controllers = SessionControllers;
 32172                foreach (var controller in controllers)
 173                {
 0174                    if (controller.IsSessionActive)
 175                    {
 0176                        return true;
 177                    }
 178                }
 179
 16180                if (controllers.Length > 0)
 181                {
 0182                    return false;
 183                }
 184
 16185                return true;
 186            }
 187        }
 188
 189        public bool SupportsMediaControl
 190        {
 191            get
 192            {
 16193                if (Capabilities is null || !Capabilities.SupportsMediaControl)
 194                {
 16195                    return false;
 196                }
 197
 0198                var controllers = SessionControllers;
 0199                foreach (var controller in controllers)
 200                {
 0201                    if (controller.SupportsMediaControl)
 202                    {
 0203                        return true;
 204                    }
 205                }
 206
 0207                return false;
 208            }
 209        }
 210
 211        public bool SupportsRemoteControl
 212        {
 213            get
 214            {
 16215                if (Capabilities is null || !Capabilities.SupportsMediaControl)
 216                {
 16217                    return false;
 218                }
 219
 0220                var controllers = SessionControllers;
 0221                foreach (var controller in controllers)
 222                {
 0223                    if (controller.SupportsMediaControl)
 224                    {
 0225                        return true;
 226                    }
 227                }
 228
 0229                return false;
 230            }
 231        }
 232
 233        public IReadOnlyList<QueueItem> NowPlayingQueue { get; set; }
 234
 235        public IReadOnlyList<BaseItemDto> NowPlayingQueueFullItems { get; set; }
 236
 237        public bool HasCustomDeviceName { get; set; }
 238
 239        public string PlaylistItemId { get; set; }
 240
 241        public string ServerId { get; set; }
 242
 243        public string UserPrimaryImageTag { get; set; }
 244
 245        /// <summary>
 246        /// Gets the supported commands.
 247        /// </summary>
 248        /// <value>The supported commands.</value>
 249        public IReadOnlyList<GeneralCommandType> SupportedCommands
 16250            => Capabilities is null ? Array.Empty<GeneralCommandType>() : Capabilities.SupportedCommands;
 251
 252        public Tuple<ISessionController, bool> EnsureController<T>(Func<SessionInfo, ISessionController> factory)
 253        {
 0254            var controllers = SessionControllers.ToList();
 0255            foreach (var controller in controllers)
 256            {
 0257                if (controller is T)
 258                {
 0259                    return new Tuple<ISessionController, bool>(controller, false);
 260                }
 261            }
 262
 0263            var newController = factory(this);
 0264            _logger.LogDebug("Creating new {0}", newController.GetType().Name);
 0265            controllers.Add(newController);
 266
 0267            SessionControllers = controllers.ToArray();
 0268            return new Tuple<ISessionController, bool>(newController, true);
 0269        }
 270
 271        public void AddController(ISessionController controller)
 272        {
 0273            SessionControllers = [..SessionControllers, controller];
 0274        }
 275
 276        public bool ContainsUser(Guid userId)
 277        {
 0278            if (UserId.Equals(userId))
 279            {
 0280                return true;
 281            }
 282
 0283            foreach (var additionalUser in AdditionalUsers)
 284            {
 0285                if (additionalUser.UserId.Equals(userId))
 286                {
 0287                    return true;
 288                }
 289            }
 290
 0291            return false;
 292        }
 293
 294        public void StartAutomaticProgress(PlaybackProgressInfo progressInfo)
 295        {
 0296            if (_disposed)
 297            {
 0298                return;
 299            }
 300
 0301            lock (_progressLock)
 302            {
 0303                _lastProgressInfo = progressInfo;
 304
 0305                if (_progressTimer is null)
 306                {
 0307                    _progressTimer = new Timer(OnProgressTimerCallback, null, 1000, 1000);
 308                }
 309                else
 310                {
 0311                    _progressTimer.Change(1000, 1000);
 312                }
 0313            }
 0314        }
 315
 316        private async void OnProgressTimerCallback(object state)
 317        {
 318            if (_disposed)
 319            {
 320                return;
 321            }
 322
 323            var progressInfo = _lastProgressInfo;
 324            if (progressInfo is null)
 325            {
 326                return;
 327            }
 328
 329            if (progressInfo.IsPaused)
 330            {
 331                return;
 332            }
 333
 334            var positionTicks = progressInfo.PositionTicks ?? 0;
 335            if (positionTicks < 0)
 336            {
 337                positionTicks = 0;
 338            }
 339
 340            var newPositionTicks = positionTicks + ProgressIncrement;
 341            var item = progressInfo.Item;
 342            long? runtimeTicks = item?.RunTimeTicks;
 343
 344            // Don't report beyond the runtime
 345            if (runtimeTicks.HasValue && newPositionTicks >= runtimeTicks.Value)
 346            {
 347                return;
 348            }
 349
 350            progressInfo.PositionTicks = newPositionTicks;
 351
 352            try
 353            {
 354                await _sessionManager.OnPlaybackProgress(progressInfo, true).ConfigureAwait(false);
 355            }
 356            catch (Exception ex)
 357            {
 358                _logger.LogError(ex, "Error reporting playback progress");
 359            }
 360        }
 361
 362        public void StopAutomaticProgress()
 363        {
 16364            lock (_progressLock)
 365            {
 16366                if (_progressTimer is not null)
 367                {
 0368                    _progressTimer.Dispose();
 0369                    _progressTimer = null;
 370                }
 371
 16372                _lastProgressInfo = null;
 16373            }
 16374        }
 375
 376        public async ValueTask DisposeAsync()
 377        {
 378            _disposed = true;
 379
 380            StopAutomaticProgress();
 381
 382            var controllers = SessionControllers.ToList();
 383            SessionControllers = Array.Empty<ISessionController>();
 384
 385            foreach (var controller in controllers)
 386            {
 387                if (controller is IAsyncDisposable disposableAsync)
 388                {
 389                    _logger.LogDebug("Disposing session controller asynchronously {TypeName}", disposableAsync.GetType()
 390                    await disposableAsync.DisposeAsync().ConfigureAwait(false);
 391                }
 392                else if (controller is IDisposable disposable)
 393                {
 394                    _logger.LogDebug("Disposing session controller synchronously {TypeName}", disposable.GetType().Name)
 395                    disposable.Dispose();
 396                }
 397            }
 398        }
 399    }
 400}