< Summary - Jellyfin

Information
Class: Jellyfin.Api.Controllers.DevicesController
Assembly: Jellyfin.Api
File(s): /srv/git/jellyfin/Jellyfin.Api/Controllers/DevicesController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 28
Coverable lines: 28
Total lines: 148
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 2/13/2026 - 12:11:21 AM Line coverage: 0% (0/16) Branch coverage: 0% (0/4) Total lines: 1404/19/2026 - 12:14:27 AM Line coverage: 0% (0/27) Branch coverage: 0% (0/8) Total lines: 1404/27/2026 - 12:15:04 AM Line coverage: 0% (0/27) Branch coverage: 0% (0/8) Total lines: 1415/22/2026 - 12:15:17 AM Line coverage: 0% (0/28) Branch coverage: 0% (0/10) Total lines: 148 2/13/2026 - 12:11:21 AM Line coverage: 0% (0/16) Branch coverage: 0% (0/4) Total lines: 1404/19/2026 - 12:14:27 AM Line coverage: 0% (0/27) Branch coverage: 0% (0/8) Total lines: 1404/27/2026 - 12:15:04 AM Line coverage: 0% (0/27) Branch coverage: 0% (0/8) Total lines: 1415/22/2026 - 12:15:17 AM Line coverage: 0% (0/28) Branch coverage: 0% (0/10) Total lines: 148

Coverage delta

Coverage delta 1 -1

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
GetDevices(...)100%210%
GetDeviceInfo(...)0%620%
GetDeviceOptions(...)0%620%
UpdateDeviceOptions()100%210%
DeleteDevice()0%4260%

File(s)

/srv/git/jellyfin/Jellyfin.Api/Controllers/DevicesController.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.ComponentModel.DataAnnotations;
 4using System.Linq;
 5using System.Threading.Tasks;
 6using Jellyfin.Api.Attributes;
 7using Jellyfin.Api.Helpers;
 8using Jellyfin.Api.ModelBinders;
 9using Jellyfin.Data.Dtos;
 10using Jellyfin.Data.Queries;
 11using MediaBrowser.Common.Api;
 12using MediaBrowser.Controller.Devices;
 13using MediaBrowser.Controller.Session;
 14using MediaBrowser.Model.Dto;
 15using MediaBrowser.Model.Querying;
 16using Microsoft.AspNetCore.Authorization;
 17using Microsoft.AspNetCore.Http;
 18using Microsoft.AspNetCore.Mvc;
 19
 20namespace Jellyfin.Api.Controllers;
 21
 22/// <summary>
 23/// Devices Controller.
 24/// </summary>
 25[Authorize(Policy = Policies.RequiresElevation)]
 26[Tags("Device")]
 27public class DevicesController : BaseJellyfinApiController
 28{
 29    private readonly IDeviceManager _deviceManager;
 30    private readonly ISessionManager _sessionManager;
 31
 32    /// <summary>
 33    /// Initializes a new instance of the <see cref="DevicesController"/> class.
 34    /// </summary>
 35    /// <param name="deviceManager">Instance of <see cref="IDeviceManager"/> interface.</param>
 36    /// <param name="sessionManager">Instance of <see cref="ISessionManager"/> interface.</param>
 037    public DevicesController(
 038        IDeviceManager deviceManager,
 039        ISessionManager sessionManager)
 40    {
 041        _deviceManager = deviceManager;
 042        _sessionManager = sessionManager;
 043    }
 44
 45    /// <summary>
 46    /// Get Devices.
 47    /// </summary>
 48    /// <param name="userId">Gets or sets the user identifier.</param>
 49    /// <response code="200">Devices retrieved.</response>
 50    /// <returns>An <see cref="OkResult"/> containing the list of devices.</returns>
 51    [HttpGet]
 52    [ProducesResponseType(StatusCodes.Status200OK)]
 53    public ActionResult<QueryResult<DeviceInfoDto>> GetDevices([FromQuery] Guid? userId)
 54    {
 055        userId = RequestHelpers.GetUserId(User, userId);
 056        return _deviceManager.GetDevicesForUser(userId);
 57    }
 58
 59    /// <summary>
 60    /// Get info for a device.
 61    /// </summary>
 62    /// <param name="id">Device Id.</param>
 63    /// <response code="200">Device info retrieved.</response>
 64    /// <response code="404">Device not found.</response>
 65    /// <returns>An <see cref="OkResult"/> containing the device info on success, or a <see cref="NotFoundResult"/> if t
 66    [HttpGet("Info")]
 67    [ProducesResponseType(StatusCodes.Status200OK)]
 68    [ProducesResponseType(StatusCodes.Status404NotFound)]
 69    public ActionResult<DeviceInfoDto> GetDeviceInfo([FromQuery, Required] string id)
 70    {
 071        var deviceInfo = _deviceManager.GetDevice(id);
 072        if (deviceInfo is null)
 73        {
 074            return NotFound();
 75        }
 76
 077        return deviceInfo;
 78    }
 79
 80    /// <summary>
 81    /// Get options for a device.
 82    /// </summary>
 83    /// <param name="id">Device Id.</param>
 84    /// <response code="200">Device options retrieved.</response>
 85    /// <response code="404">Device not found.</response>
 86    /// <returns>An <see cref="OkResult"/> containing the device info on success, or a <see cref="NotFoundResult"/> if t
 87    [HttpGet("Options")]
 88    [ProducesResponseType(StatusCodes.Status200OK)]
 89    [ProducesResponseType(StatusCodes.Status404NotFound)]
 90    public ActionResult<DeviceOptionsDto> GetDeviceOptions([FromQuery, Required] string id)
 91    {
 092        var deviceInfo = _deviceManager.GetDeviceOptions(id);
 093        if (deviceInfo is null)
 94        {
 095            return NotFound();
 96        }
 97
 098        return deviceInfo;
 99    }
 100
 101    /// <summary>
 102    /// Update device options.
 103    /// </summary>
 104    /// <param name="id">Device Id.</param>
 105    /// <param name="deviceOptions">Device Options.</param>
 106    /// <response code="204">Device options updated.</response>
 107    /// <returns>A <see cref="NoContentResult"/>.</returns>
 108    [HttpPost("Options")]
 109    [ProducesResponseType(StatusCodes.Status204NoContent)]
 110    public async Task<ActionResult> UpdateDeviceOptions(
 111        [FromQuery, Required] string id,
 112        [FromBody, Required] DeviceOptionsDto deviceOptions)
 113    {
 0114        await _deviceManager.UpdateDeviceOptions(id, deviceOptions.CustomName).ConfigureAwait(false);
 0115        return NoContent();
 0116    }
 117
 118    /// <summary>
 119    /// Deletes devices.
 120    /// </summary>
 121    /// <param name="id">Device Ids.</param>
 122    /// <response code="204">Device deleted.</response>
 123    /// <response code="400">A requested device is invalid.</response>
 124    /// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="BadRequestResult"/> if a requested device i
 125    [HttpDelete]
 126    [ProducesResponseType(StatusCodes.Status204NoContent)]
 127    [ProducesResponseType(StatusCodes.Status400BadRequest)]
 128    public async Task<ActionResult> DeleteDevice([FromQuery] string[] id)
 129    {
 0130        var devices = id.Select(_deviceManager.GetDevice).ToArray();
 0131        if (devices.Any(f => f is null))
 132        {
 0133            return BadRequest();
 134        }
 135
 0136        foreach (var device in devices)
 137        {
 0138            var sessions = _deviceManager.GetDevices(new DeviceQuery { DeviceId = device!.Id });
 139
 0140            foreach (var session in sessions.Items)
 141            {
 0142                await _sessionManager.Logout(session).ConfigureAwait(false);
 143            }
 144        }
 145
 0146        return NoContent();
 0147    }
 148}