< Summary - Jellyfin

Information
Class: Jellyfin.Api.Controllers.ItemLookupController
Assembly: Jellyfin.Api
File(s): /srv/git/jellyfin/Jellyfin.Api/Controllers/ItemLookupController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 73
Coverable lines: 73
Total lines: 283
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 4
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 5/16/2026 - 12:15:55 AM Line coverage: 0% (0/73) Branch coverage: 0% (0/4) Total lines: 28210/29/2026 - 12:17:11 AM Line coverage: 0% (0/73) Branch coverage: 0% (0/4) Total lines: 283 5/16/2026 - 12:15:55 AM Line coverage: 0% (0/73) Branch coverage: 0% (0/4) Total lines: 28210/29/2026 - 12:17:11 AM Line coverage: 0% (0/73) Branch coverage: 0% (0/4) Total lines: 283

Coverage delta

Coverage delta 1 -1

Metrics

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.ComponentModel.DataAnnotations;
 4using System.Threading;
 5using System.Threading.Tasks;
 6using Jellyfin.Api.Constants;
 7using Jellyfin.Api.Extensions;
 8using Jellyfin.Api.Helpers;
 9using MediaBrowser.Common.Api;
 10using MediaBrowser.Controller.Entities;
 11using MediaBrowser.Controller.Entities.Audio;
 12using MediaBrowser.Controller.Entities.Movies;
 13using MediaBrowser.Controller.Entities.TV;
 14using MediaBrowser.Controller.Library;
 15using MediaBrowser.Controller.Providers;
 16using MediaBrowser.Model.Entities;
 17using MediaBrowser.Model.IO;
 18using MediaBrowser.Model.Providers;
 19using Microsoft.AspNetCore.Authorization;
 20using Microsoft.AspNetCore.Http;
 21using Microsoft.AspNetCore.Mvc;
 22using Microsoft.Extensions.Logging;
 23
 24namespace Jellyfin.Api.Controllers;
 25
 26/// <summary>
 27/// Item lookup controller.
 28/// </summary>
 29[Route("")]
 30[Authorize]
 31public class ItemLookupController : BaseJellyfinApiController
 32{
 33    private readonly IProviderManager _providerManager;
 34    private readonly IFileSystem _fileSystem;
 35    private readonly ILibraryManager _libraryManager;
 36    private readonly ILogger<ItemLookupController> _logger;
 37
 38    /// <summary>
 39    /// Initializes a new instance of the <see cref="ItemLookupController"/> class.
 40    /// </summary>
 41    /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
 42    /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
 43    /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
 44    /// <param name="logger">Instance of the <see cref="ILogger{ItemLookupController}"/> interface.</param>
 045    public ItemLookupController(
 046        IProviderManager providerManager,
 047        IFileSystem fileSystem,
 048        ILibraryManager libraryManager,
 049        ILogger<ItemLookupController> logger)
 50    {
 051        _providerManager = providerManager;
 052        _fileSystem = fileSystem;
 053        _libraryManager = libraryManager;
 054        _logger = logger;
 055    }
 56
 57    /// <summary>
 58    /// Get the item's external id info.
 59    /// </summary>
 60    /// <param name="itemId">Item id.</param>
 61    /// <response code="200">External id info retrieved.</response>
 62    /// <response code="404">Item not found.</response>
 63    /// <returns>List of external id info.</returns>
 64    [HttpGet("Items/{itemId}/ExternalIdInfos")]
 65    [Authorize(Policy = Policies.RequiresElevation)]
 66    [ProducesResponseType(StatusCodes.Status200OK)]
 67    [ProducesResponseType(StatusCodes.Status404NotFound)]
 68    public ActionResult<IEnumerable<ExternalIdInfo>> GetExternalIdInfos([FromRoute, Required] Guid itemId)
 69    {
 070        var item = _libraryManager.GetItemById<BaseItem>(itemId, User.GetUserId());
 071        if (item is null)
 72        {
 073            return NotFound();
 74        }
 75
 076        return Ok(_providerManager.GetExternalIdInfos(item));
 77    }
 78
 79    /// <summary>
 80    /// Get movie remote search.
 81    /// </summary>
 82    /// <param name="query">Remote search query.</param>
 83    /// <response code="200">Movie remote search executed.</response>
 84    /// <returns>
 85    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 86    /// The task result contains an <see cref="OkResult"/> containing the list of remote search results.
 87    /// </returns>
 88    [HttpPost("Items/RemoteSearch/Movie")]
 89    public async Task<ActionResult<IEnumerable<RemoteSearchResult>>> GetMovieRemoteSearchResults([FromBody, Required] Re
 90    {
 091        var results = await _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(query, CancellationToken.None)
 092            .ConfigureAwait(false);
 093        return Ok(results);
 094    }
 95
 96    /// <summary>
 97    /// Get trailer remote search.
 98    /// </summary>
 99    /// <param name="query">Remote search query.</param>
 100    /// <response code="200">Trailer remote search executed.</response>
 101    /// <returns>
 102    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 103    /// The task result contains an <see cref="OkResult"/> containing the list of remote search results.
 104    /// </returns>
 105    [HttpPost("Items/RemoteSearch/Trailer")]
 106    public async Task<ActionResult<IEnumerable<RemoteSearchResult>>> GetTrailerRemoteSearchResults([FromBody, Required] 
 107    {
 0108        var results = await _providerManager.GetRemoteSearchResults<Trailer, TrailerInfo>(query, CancellationToken.None)
 0109            .ConfigureAwait(false);
 0110        return Ok(results);
 0111    }
 112
 113    /// <summary>
 114    /// Get music video remote search.
 115    /// </summary>
 116    /// <param name="query">Remote search query.</param>
 117    /// <response code="200">Music video remote search executed.</response>
 118    /// <returns>
 119    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 120    /// The task result contains an <see cref="OkResult"/> containing the list of remote search results.
 121    /// </returns>
 122    [HttpPost("Items/RemoteSearch/MusicVideo")]
 123    public async Task<ActionResult<IEnumerable<RemoteSearchResult>>> GetMusicVideoRemoteSearchResults([FromBody, Require
 124    {
 0125        var results = await _providerManager.GetRemoteSearchResults<MusicVideo, MusicVideoInfo>(query, CancellationToken
 0126            .ConfigureAwait(false);
 0127        return Ok(results);
 0128    }
 129
 130    /// <summary>
 131    /// Get series remote search.
 132    /// </summary>
 133    /// <param name="query">Remote search query.</param>
 134    /// <response code="200">Series remote search executed.</response>
 135    /// <returns>
 136    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 137    /// The task result contains an <see cref="OkResult"/> containing the list of remote search results.
 138    /// </returns>
 139    [HttpPost("Items/RemoteSearch/Series")]
 140    public async Task<ActionResult<IEnumerable<RemoteSearchResult>>> GetSeriesRemoteSearchResults([FromBody, Required] R
 141    {
 0142        var results = await _providerManager.GetRemoteSearchResults<Series, SeriesInfo>(query, CancellationToken.None)
 0143            .ConfigureAwait(false);
 0144        return Ok(results);
 0145    }
 146
 147    /// <summary>
 148    /// Get box set remote search.
 149    /// </summary>
 150    /// <param name="query">Remote search query.</param>
 151    /// <response code="200">Box set remote search executed.</response>
 152    /// <returns>
 153    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 154    /// The task result contains an <see cref="OkResult"/> containing the list of remote search results.
 155    /// </returns>
 156    [HttpPost("Items/RemoteSearch/BoxSet")]
 157    public async Task<ActionResult<IEnumerable<RemoteSearchResult>>> GetBoxSetRemoteSearchResults([FromBody, Required] R
 158    {
 0159        var results = await _providerManager.GetRemoteSearchResults<BoxSet, BoxSetInfo>(query, CancellationToken.None)
 0160            .ConfigureAwait(false);
 0161        return Ok(results);
 0162    }
 163
 164    /// <summary>
 165    /// Get music artist remote search.
 166    /// </summary>
 167    /// <param name="query">Remote search query.</param>
 168    /// <response code="200">Music artist remote search executed.</response>
 169    /// <returns>
 170    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 171    /// The task result contains an <see cref="OkResult"/> containing the list of remote search results.
 172    /// </returns>
 173    [HttpPost("Items/RemoteSearch/MusicArtist")]
 174    public async Task<ActionResult<IEnumerable<RemoteSearchResult>>> GetMusicArtistRemoteSearchResults([FromBody, Requir
 175    {
 0176        var results = await _providerManager.GetRemoteSearchResults<MusicArtist, ArtistInfo>(query, CancellationToken.No
 0177            .ConfigureAwait(false);
 0178        return Ok(results);
 0179    }
 180
 181    /// <summary>
 182    /// Get music album remote search.
 183    /// </summary>
 184    /// <param name="query">Remote search query.</param>
 185    /// <response code="200">Music album remote search executed.</response>
 186    /// <returns>
 187    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 188    /// The task result contains an <see cref="OkResult"/> containing the list of remote search results.
 189    /// </returns>
 190    [HttpPost("Items/RemoteSearch/MusicAlbum")]
 191    public async Task<ActionResult<IEnumerable<RemoteSearchResult>>> GetMusicAlbumRemoteSearchResults([FromBody, Require
 192    {
 0193        var results = await _providerManager.GetRemoteSearchResults<MusicAlbum, AlbumInfo>(query, CancellationToken.None
 0194            .ConfigureAwait(false);
 0195        return Ok(results);
 0196    }
 197
 198    /// <summary>
 199    /// Get person remote search.
 200    /// </summary>
 201    /// <param name="query">Remote search query.</param>
 202    /// <response code="200">Person remote search executed.</response>
 203    /// <returns>
 204    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 205    /// The task result contains an <see cref="OkResult"/> containing the list of remote search results.
 206    /// </returns>
 207    [HttpPost("Items/RemoteSearch/Person")]
 208    [Authorize(Policy = Policies.RequiresElevation)]
 209    public async Task<ActionResult<IEnumerable<RemoteSearchResult>>> GetPersonRemoteSearchResults([FromBody, Required] R
 210    {
 0211        var results = await _providerManager.GetRemoteSearchResults<Person, PersonLookupInfo>(query, CancellationToken.N
 0212            .ConfigureAwait(false);
 0213        return Ok(results);
 0214    }
 215
 216    /// <summary>
 217    /// Get book remote search.
 218    /// </summary>
 219    /// <param name="query">Remote search query.</param>
 220    /// <response code="200">Book remote search executed.</response>
 221    /// <returns>
 222    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 223    /// The task result contains an <see cref="OkResult"/> containing the list of remote search results.
 224    /// </returns>
 225    [HttpPost("Items/RemoteSearch/Book")]
 226    public async Task<ActionResult<IEnumerable<RemoteSearchResult>>> GetBookRemoteSearchResults([FromBody, Required] Rem
 227    {
 0228        var results = await _providerManager.GetRemoteSearchResults<Book, BookInfo>(query, CancellationToken.None)
 0229            .ConfigureAwait(false);
 0230        return Ok(results);
 0231    }
 232
 233    /// <summary>
 234    /// Applies search criteria to an item and refreshes metadata.
 235    /// </summary>
 236    /// <param name="itemId">Item id.</param>
 237    /// <param name="searchResult">The remote search result.</param>
 238    /// <param name="replaceAllImages">Optional. Whether or not to replace all images. Default: True.</param>
 239    /// <response code="204">Item metadata refreshed.</response>
 240    /// <response code="404">Item not found.</response>
 241    /// <returns>
 242    /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
 243    /// The task result contains an <see cref="NoContentResult"/>.
 244    /// </returns>
 245    [HttpPost("Items/RemoteSearch/Apply/{itemId}")]
 246    [Authorize(Policy = Policies.RequiresElevation)]
 247    [ProducesResponseType(StatusCodes.Status204NoContent)]
 248    [ProducesResponseType(StatusCodes.Status404NotFound)]
 249    public async Task<ActionResult> ApplySearchCriteria(
 250        [FromRoute, Required] Guid itemId,
 251        [FromBody, Required] RemoteSearchResult searchResult,
 252        [FromQuery] bool replaceAllImages = true)
 253    {
 0254        var item = _libraryManager.GetItemById<BaseItem>(itemId, User.GetUserId());
 0255        if (item is null)
 256        {
 0257            return NotFound();
 258        }
 259
 0260        _logger.LogInformation(
 0261            "Setting provider id's to item {ItemId}-{ItemName}: {@ProviderIds}",
 0262            item.Id,
 0263            item.Name,
 0264            searchResult.ProviderIds);
 265
 266        // Since the refresh process won't erase provider Ids, we need to set this explicitly now.
 0267        item.SetProviderIds(searchResult.ProviderIds);
 0268        await _providerManager.RefreshFullItem(
 0269            item,
 0270            new MetadataRefreshOptions(new DirectoryService(_fileSystem))
 0271            {
 0272                MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
 0273                ImageRefreshMode = MetadataRefreshMode.FullRefresh,
 0274                ReplaceAllMetadata = true,
 0275                ReplaceAllImages = replaceAllImages,
 0276                SearchResult = searchResult,
 0277                RemoveOldMetadata = true
 0278            },
 0279            CancellationToken.None).ConfigureAwait(false);
 280
 0281        return NoContent();
 0282    }
 283}