using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Constants; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Controllers { /// /// Item lookup controller. /// [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class ItemLookupController : BaseJellyfinApiController { private readonly IProviderManager _providerManager; private readonly IFileSystem _fileSystem; private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. public ItemLookupController( IProviderManager providerManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILogger logger) { _providerManager = providerManager; _fileSystem = fileSystem; _libraryManager = libraryManager; _logger = logger; } /// /// Get the item's external id info. /// /// Item id. /// External id info retrieved. /// Item not found. /// List of external id info. [HttpGet("Items/{itemId}/ExternalIdInfos")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetExternalIdInfos([FromRoute, Required] Guid itemId) { var item = _libraryManager.GetItemById(itemId); if (item is null) { return NotFound(); } return Ok(_providerManager.GetExternalIdInfos(item)); } /// /// Get movie remote search. /// /// Remote search query. /// Movie remote search executed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// [HttpPost("Items/RemoteSearch/Movie")] public async Task>> GetMovieRemoteSearchResults([FromBody, Required] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) .ConfigureAwait(false); return Ok(results); } /// /// Get trailer remote search. /// /// Remote search query. /// Trailer remote search executed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// [HttpPost("Items/RemoteSearch/Trailer")] public async Task>> GetTrailerRemoteSearchResults([FromBody, Required] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) .ConfigureAwait(false); return Ok(results); } /// /// Get music video remote search. /// /// Remote search query. /// Music video remote search executed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// [HttpPost("Items/RemoteSearch/MusicVideo")] public async Task>> GetMusicVideoRemoteSearchResults([FromBody, Required] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) .ConfigureAwait(false); return Ok(results); } /// /// Get series remote search. /// /// Remote search query. /// Series remote search executed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// [HttpPost("Items/RemoteSearch/Series")] public async Task>> GetSeriesRemoteSearchResults([FromBody, Required] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) .ConfigureAwait(false); return Ok(results); } /// /// Get box set remote search. /// /// Remote search query. /// Box set remote search executed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// [HttpPost("Items/RemoteSearch/BoxSet")] public async Task>> GetBoxSetRemoteSearchResults([FromBody, Required] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) .ConfigureAwait(false); return Ok(results); } /// /// Get music artist remote search. /// /// Remote search query. /// Music artist remote search executed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// [HttpPost("Items/RemoteSearch/MusicArtist")] public async Task>> GetMusicArtistRemoteSearchResults([FromBody, Required] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) .ConfigureAwait(false); return Ok(results); } /// /// Get music album remote search. /// /// Remote search query. /// Music album remote search executed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// [HttpPost("Items/RemoteSearch/MusicAlbum")] public async Task>> GetMusicAlbumRemoteSearchResults([FromBody, Required] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) .ConfigureAwait(false); return Ok(results); } /// /// Get person remote search. /// /// Remote search query. /// Person remote search executed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// [HttpPost("Items/RemoteSearch/Person")] [Authorize(Policy = Policies.RequiresElevation)] public async Task>> GetPersonRemoteSearchResults([FromBody, Required] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) .ConfigureAwait(false); return Ok(results); } /// /// Get book remote search. /// /// Remote search query. /// Book remote search executed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// [HttpPost("Items/RemoteSearch/Book")] public async Task>> GetBookRemoteSearchResults([FromBody, Required] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) .ConfigureAwait(false); return Ok(results); } /// /// Applies search criteria to an item and refreshes metadata. /// /// Item id. /// The remote search result. /// Optional. Whether or not to replace all images. Default: True. /// Item metadata refreshed. /// /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an . /// [HttpPost("Items/RemoteSearch/Apply/{itemId}")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task ApplySearchCriteria( [FromRoute, Required] Guid itemId, [FromBody, Required] RemoteSearchResult searchResult, [FromQuery] bool replaceAllImages = true) { var item = _libraryManager.GetItemById(itemId); _logger.LogInformation( "Setting provider id's to item {0}-{1}: {2}", item.Id, item.Name, JsonSerializer.Serialize(searchResult.ProviderIds)); // Since the refresh process won't erase provider Ids, we need to set this explicitly now. item.ProviderIds = searchResult.ProviderIds; await _providerManager.RefreshFullItem( item, new MetadataRefreshOptions(new DirectoryService(_fileSystem)) { MetadataRefreshMode = MetadataRefreshMode.FullRefresh, ImageRefreshMode = MetadataRefreshMode.FullRefresh, ReplaceAllMetadata = true, ReplaceAllImages = replaceAllImages, SearchResult = searchResult, RemoveOldMetadata = true }, CancellationToken.None).ConfigureAwait(false); return NoContent(); } } }