< Summary - Jellyfin

Information
Class: Jellyfin.Api.Controllers.LibraryController
Assembly: Jellyfin.Api
File(s): /srv/git/jellyfin/Jellyfin.Api/Controllers/LibraryController.cs
Line coverage
24%
Covered lines: 108
Uncovered lines: 326
Coverable lines: 434
Total lines: 1006
Line coverage: 24.8%
Branch coverage
15%
Covered branches: 29
Total branches: 192
Branch coverage: 15.1%
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: 23.5% (97/412) Branch coverage: 14% (27/192) Total lines: 10574/19/2026 - 12:14:27 AM Line coverage: 23.1% (105/453) Branch coverage: 13.6% (29/212) Total lines: 10574/30/2026 - 12:14:58 AM Line coverage: 23.1% (105/453) Branch coverage: 13.6% (29/212) Total lines: 10435/4/2026 - 12:15:16 AM Line coverage: 23.9% (105/439) Branch coverage: 13.6% (29/212) Total lines: 10245/16/2026 - 12:15:55 AM Line coverage: 24.8% (108/434) Branch coverage: 15.1% (29/192) Total lines: 1006 2/13/2026 - 12:11:21 AM Line coverage: 23.5% (97/412) Branch coverage: 14% (27/192) Total lines: 10574/19/2026 - 12:14:27 AM Line coverage: 23.1% (105/453) Branch coverage: 13.6% (29/212) Total lines: 10574/30/2026 - 12:14:58 AM Line coverage: 23.1% (105/453) Branch coverage: 13.6% (29/212) Total lines: 10435/4/2026 - 12:15:16 AM Line coverage: 23.9% (105/439) Branch coverage: 13.6% (29/212) Total lines: 10245/16/2026 - 12:15:55 AM Line coverage: 24.8% (108/434) Branch coverage: 15.1% (29/192) Total lines: 1006

Coverage delta

Coverage delta 2 -2

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetFile(...)50%2275%
GetThemeSongs(...)16.66%1001836.66%
GetThemeVideos(...)16.66%1001836.66%
GetThemeMedia(...)37.5%9871.42%
RefreshLibrary()100%210%
DeleteItem(...)33.33%271252.94%
DeleteItems(...)44.44%461855.55%
GetItemCounts(...)0%620%
GetAncestors(...)20%301041.17%
GetPhysicalPaths()100%210%
GetMediaFolders(...)0%620%
PostUpdatedSeries(...)0%620%
PostUpdatedMovies(...)0%4260%
PostUpdatedMedia(...)0%2040%
GetDownload()10%1232036.36%
GetSimilarItems()21.42%541441.37%
GetLibraryOptionsInfo(...)0%2040%
TranslateParentItem(...)0%620%
LogDownloadAsync()100%210%
GetRepresentativeItemTypes(...)0%210140%
IsSaverEnabledByDefault(...)0%2040%
IsMetadataFetcherEnabledByDefault(...)0%210140%
IsImageFetcherEnabledByDefault(...)0%342180%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.ComponentModel.DataAnnotations;
 4using System.Globalization;
 5using System.IO;
 6using System.Linq;
 7using System.Threading;
 8using System.Threading.Tasks;
 9using Jellyfin.Api.Attributes;
 10using Jellyfin.Api.Extensions;
 11using Jellyfin.Api.Helpers;
 12using Jellyfin.Api.ModelBinders;
 13using Jellyfin.Api.Models.LibraryDtos;
 14using Jellyfin.Data.Enums;
 15using Jellyfin.Database.Implementations.Entities;
 16using Jellyfin.Database.Implementations.Enums;
 17using Jellyfin.Extensions;
 18using MediaBrowser.Common.Api;
 19using MediaBrowser.Common.Extensions;
 20using MediaBrowser.Controller.Configuration;
 21using MediaBrowser.Controller.Dto;
 22using MediaBrowser.Controller.Entities;
 23using MediaBrowser.Controller.Entities.Audio;
 24using MediaBrowser.Controller.Entities.Movies;
 25using MediaBrowser.Controller.Entities.TV;
 26using MediaBrowser.Controller.IO;
 27using MediaBrowser.Controller.Library;
 28using MediaBrowser.Controller.Providers;
 29using MediaBrowser.Model.Activity;
 30using MediaBrowser.Model.Configuration;
 31using MediaBrowser.Model.Dto;
 32using MediaBrowser.Model.Entities;
 33using MediaBrowser.Model.Globalization;
 34using MediaBrowser.Model.Net;
 35using MediaBrowser.Model.Querying;
 36using Microsoft.AspNetCore.Authorization;
 37using Microsoft.AspNetCore.Http;
 38using Microsoft.AspNetCore.Mvc;
 39using Microsoft.Extensions.Logging;
 40
 41namespace Jellyfin.Api.Controllers;
 42
 43/// <summary>
 44/// Library Controller.
 45/// </summary>
 46[Route("")]
 47public class LibraryController : BaseJellyfinApiController
 48{
 49    private readonly IProviderManager _providerManager;
 50    private readonly ISimilarItemsManager _similarItemsManager;
 51    private readonly ILibraryManager _libraryManager;
 52    private readonly IUserManager _userManager;
 53    private readonly IDtoService _dtoService;
 54    private readonly IActivityManager _activityManager;
 55    private readonly ILocalizationManager _localization;
 56    private readonly ILibraryMonitor _libraryMonitor;
 57    private readonly ILogger<LibraryController> _logger;
 58    private readonly IServerConfigurationManager _serverConfigurationManager;
 59
 60    /// <summary>
 61    /// Initializes a new instance of the <see cref="LibraryController"/> class.
 62    /// </summary>
 63    /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
 64    /// <param name="similarItemsManager">Instance of the <see cref="ISimilarItemsManager"/> interface.</param>
 65    /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
 66    /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
 67    /// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
 68    /// <param name="activityManager">Instance of the <see cref="IActivityManager"/> interface.</param>
 69    /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
 70    /// <param name="libraryMonitor">Instance of the <see cref="ILibraryMonitor"/> interface.</param>
 71    /// <param name="logger">Instance of the <see cref="ILogger{LibraryController}"/> interface.</param>
 72    /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</p
 1473    public LibraryController(
 1474        IProviderManager providerManager,
 1475        ISimilarItemsManager similarItemsManager,
 1476        ILibraryManager libraryManager,
 1477        IUserManager userManager,
 1478        IDtoService dtoService,
 1479        IActivityManager activityManager,
 1480        ILocalizationManager localization,
 1481        ILibraryMonitor libraryMonitor,
 1482        ILogger<LibraryController> logger,
 1483        IServerConfigurationManager serverConfigurationManager)
 84    {
 1485        _providerManager = providerManager;
 1486        _similarItemsManager = similarItemsManager;
 1487        _libraryManager = libraryManager;
 1488        _userManager = userManager;
 1489        _dtoService = dtoService;
 1490        _activityManager = activityManager;
 1491        _localization = localization;
 1492        _libraryMonitor = libraryMonitor;
 1493        _logger = logger;
 1494        _serverConfigurationManager = serverConfigurationManager;
 1495    }
 96
 97    /// <summary>
 98    /// Get the original file of an item.
 99    /// </summary>
 100    /// <param name="itemId">The item id.</param>
 101    /// <response code="200">File stream returned.</response>
 102    /// <response code="404">Item not found.</response>
 103    /// <returns>A <see cref="FileStreamResult"/> with the original file.</returns>
 104    [HttpGet("Items/{itemId}/File")]
 105    [Authorize]
 106    [ProducesResponseType(StatusCodes.Status200OK)]
 107    [ProducesResponseType(StatusCodes.Status404NotFound)]
 108    [ProducesFile("video/*", "audio/*")]
 109    public ActionResult GetFile([FromRoute, Required] Guid itemId)
 110    {
 1111        var item = _libraryManager.GetItemById<BaseItem>(itemId, User.GetUserId());
 1112        if (item is null)
 113        {
 1114            return NotFound();
 115        }
 116
 0117        return PhysicalFile(item.Path, MimeTypes.GetMimeType(item.Path), true);
 118    }
 119
 120    /// <summary>
 121    /// Get theme songs for an item.
 122    /// </summary>
 123    /// <param name="itemId">The item id.</param>
 124    /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
 125    /// <param name="inheritFromParent">Optional. Determines whether or not parent items should be searched for theme me
 126    /// <param name="sortBy">Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Ar
 127    /// <param name="sortOrder">Optional. Sort Order - Ascending, Descending.</param>
 128    /// <response code="200">Theme songs returned.</response>
 129    /// <response code="404">Item not found.</response>
 130    /// <returns>The item theme songs.</returns>
 131    [HttpGet("Items/{itemId}/ThemeSongs")]
 132    [Authorize]
 133    [ProducesResponseType(StatusCodes.Status200OK)]
 134    [ProducesResponseType(StatusCodes.Status404NotFound)]
 135    public ActionResult<ThemeMediaResult> GetThemeSongs(
 136        [FromRoute, Required] Guid itemId,
 137        [FromQuery] Guid? userId,
 138        [FromQuery] bool inheritFromParent = false,
 139        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[]? sortBy = null,
 140        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[]? sortOrder = null)
 141    {
 2142        userId = RequestHelpers.GetUserId(User, userId);
 2143        var user = userId.IsNullOrEmpty()
 2144            ? null
 2145            : _userManager.GetUserById(userId.Value);
 146
 2147        var item = itemId.IsEmpty()
 2148            ? (userId.IsNullOrEmpty()
 2149                ? _libraryManager.RootFolder
 2150                : _libraryManager.GetUserRootFolder())
 2151            : _libraryManager.GetItemById<BaseItem>(itemId, user);
 2152        if (item is null)
 153        {
 2154            return NotFound();
 155        }
 156
 0157        sortOrder ??= [];
 0158        sortBy ??= [];
 0159        var orderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder);
 160
 161        IReadOnlyList<BaseItem> themeItems;
 162
 0163        while (true)
 164        {
 0165            themeItems = item.GetThemeSongs(user, orderBy);
 166
 0167            if (themeItems.Count > 0 || !inheritFromParent)
 168            {
 169                break;
 170            }
 171
 0172            var parent = item.GetParent();
 0173            if (parent is null)
 174            {
 175                break;
 176            }
 177
 0178            item = parent;
 179        }
 180
 0181        var dtoOptions = new DtoOptions();
 0182        var items = themeItems
 0183            .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item))
 0184            .ToArray();
 185
 0186        return new ThemeMediaResult
 0187        {
 0188            Items = items,
 0189            TotalRecordCount = items.Length,
 0190            OwnerId = item.Id
 0191        };
 192    }
 193
 194    /// <summary>
 195    /// Get theme videos for an item.
 196    /// </summary>
 197    /// <param name="itemId">The item id.</param>
 198    /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
 199    /// <param name="inheritFromParent">Optional. Determines whether or not parent items should be searched for theme me
 200    /// <param name="sortBy">Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Ar
 201    /// <param name="sortOrder">Optional. Sort Order - Ascending, Descending.</param>
 202    /// <response code="200">Theme videos returned.</response>
 203    /// <response code="404">Item not found.</response>
 204    /// <returns>The item theme videos.</returns>
 205    [HttpGet("Items/{itemId}/ThemeVideos")]
 206    [Authorize]
 207    [ProducesResponseType(StatusCodes.Status200OK)]
 208    [ProducesResponseType(StatusCodes.Status404NotFound)]
 209    public ActionResult<ThemeMediaResult> GetThemeVideos(
 210        [FromRoute, Required] Guid itemId,
 211        [FromQuery] Guid? userId,
 212        [FromQuery] bool inheritFromParent = false,
 213        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[]? sortBy = null,
 214        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[]? sortOrder = null)
 215    {
 2216        userId = RequestHelpers.GetUserId(User, userId);
 2217        var user = userId.IsNullOrEmpty()
 2218            ? null
 2219            : _userManager.GetUserById(userId.Value);
 2220        var item = itemId.IsEmpty()
 2221            ? (userId.IsNullOrEmpty()
 2222                ? _libraryManager.RootFolder
 2223                : _libraryManager.GetUserRootFolder())
 2224            : _libraryManager.GetItemById<BaseItem>(itemId, user);
 2225        if (item is null)
 226        {
 2227            return NotFound();
 228        }
 229
 0230        sortOrder ??= [];
 0231        sortBy ??= [];
 0232        var orderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder);
 233
 234        IEnumerable<BaseItem> themeItems;
 235
 0236        while (true)
 237        {
 0238            themeItems = item.GetThemeVideos(user, orderBy);
 239
 0240            if (themeItems.Any() || !inheritFromParent)
 241            {
 242                break;
 243            }
 244
 0245            var parent = item.GetParent();
 0246            if (parent is null)
 247            {
 248                break;
 249            }
 250
 0251            item = parent;
 252        }
 253
 0254        var dtoOptions = new DtoOptions();
 0255        var items = themeItems
 0256            .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item))
 0257            .ToArray();
 258
 0259        return new ThemeMediaResult
 0260        {
 0261            Items = items,
 0262            TotalRecordCount = items.Length,
 0263            OwnerId = item.Id
 0264        };
 265    }
 266
 267    /// <summary>
 268    /// Get theme songs and videos for an item.
 269    /// </summary>
 270    /// <param name="itemId">The item id.</param>
 271    /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
 272    /// <param name="inheritFromParent">Optional. Determines whether or not parent items should be searched for theme me
 273    /// <param name="sortBy">Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Ar
 274    /// <param name="sortOrder">Optional. Sort Order - Ascending, Descending.</param>
 275    /// <response code="200">Theme songs and videos returned.</response>
 276    /// <response code="404">Item not found.</response>
 277    /// <returns>The item theme videos.</returns>
 278    [HttpGet("Items/{itemId}/ThemeMedia")]
 279    [Authorize]
 280    [ProducesResponseType(StatusCodes.Status200OK)]
 281    public ActionResult<AllThemeMediaResult> GetThemeMedia(
 282        [FromRoute, Required] Guid itemId,
 283        [FromQuery] Guid? userId,
 284        [FromQuery] bool inheritFromParent = false,
 285        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[]? sortBy = null,
 286        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[]? sortOrder = null)
 287    {
 1288        var themeSongs = GetThemeSongs(
 1289            itemId,
 1290            userId,
 1291            inheritFromParent,
 1292            sortBy,
 1293            sortOrder);
 294
 1295        var themeVideos = GetThemeVideos(
 1296            itemId,
 1297            userId,
 1298            inheritFromParent,
 1299            sortBy,
 1300            sortOrder);
 301
 1302        if (themeSongs.Result is StatusCodeResult { StatusCode: StatusCodes.Status404NotFound }
 1303            || themeVideos.Result is StatusCodeResult { StatusCode: StatusCodes.Status404NotFound })
 304        {
 1305            return NotFound();
 306        }
 307
 0308        return new AllThemeMediaResult
 0309        {
 0310            ThemeSongsResult = themeSongs.Value,
 0311            ThemeVideosResult = themeVideos.Value,
 0312            SoundtrackSongsResult = new ThemeMediaResult()
 0313        };
 314    }
 315
 316    /// <summary>
 317    /// Starts a library scan.
 318    /// </summary>
 319    /// <response code="204">Library scan started.</response>
 320    /// <returns>A <see cref="NoContentResult"/>.</returns>
 321    [HttpPost("Library/Refresh")]
 322    [Authorize(Policy = Policies.RequiresElevation)]
 323    [ProducesResponseType(StatusCodes.Status204NoContent)]
 324    public async Task<ActionResult> RefreshLibrary()
 325    {
 326        try
 327        {
 0328            await _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None).ConfigureAwait(fa
 0329        }
 0330        catch (Exception ex)
 331        {
 0332            _logger.LogError(ex, "Error refreshing library");
 0333        }
 334
 0335        return NoContent();
 0336    }
 337
 338    /// <summary>
 339    /// Deletes an item from the library and filesystem.
 340    /// </summary>
 341    /// <param name="itemId">The item id.</param>
 342    /// <response code="204">Item deleted.</response>
 343    /// <response code="401">Unauthorized access.</response>
 344    /// <response code="404">Item not found.</response>
 345    /// <returns>A <see cref="NoContentResult"/>.</returns>
 346    [HttpDelete("Items/{itemId}")]
 347    [Authorize]
 348    [ProducesResponseType(StatusCodes.Status204NoContent)]
 349    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
 350    [ProducesResponseType(StatusCodes.Status404NotFound)]
 351    public ActionResult DeleteItem(Guid itemId)
 352    {
 1353        var userId = User.GetUserId();
 1354        var isApiKey = User.GetIsApiKey();
 1355        var user = userId.IsEmpty() && isApiKey
 1356            ? null
 1357            : _userManager.GetUserById(userId);
 358
 1359        if (user is null && !isApiKey)
 360        {
 0361            return NotFound();
 362        }
 363
 1364        var item = _libraryManager.GetItemById<BaseItem>(itemId, user);
 1365        if (item is null)
 366        {
 1367            return NotFound();
 368        }
 369
 0370        if (user is not null && !item.CanDelete(user))
 371        {
 0372            return Unauthorized("Unauthorized access");
 373        }
 374
 0375        _libraryManager.DeleteItem(
 0376            item,
 0377            new DeleteOptions { DeleteFileLocation = true },
 0378            true);
 379
 0380        return NoContent();
 381    }
 382
 383    /// <summary>
 384    /// Deletes items from the library and filesystem.
 385    /// </summary>
 386    /// <param name="ids">The item ids.</param>
 387    /// <response code="204">Items deleted.</response>
 388    /// <response code="401">Unauthorized access.</response>
 389    /// <returns>A <see cref="NoContentResult"/>.</returns>
 390    [HttpDelete("Items")]
 391    [Authorize]
 392    [ProducesResponseType(StatusCodes.Status204NoContent)]
 393    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
 394    [ProducesResponseType(StatusCodes.Status404NotFound)]
 395    public ActionResult DeleteItems([FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] ids)
 396    {
 1397        var isApiKey = User.GetIsApiKey();
 1398        var userId = User.GetUserId();
 1399        var user = !isApiKey && !userId.IsEmpty()
 1400            ? _userManager.GetUserById(userId) ?? throw new ResourceNotFoundException()
 1401            : null;
 402
 1403        if (!isApiKey && user is null)
 404        {
 0405            return Unauthorized("Unauthorized access");
 406        }
 407
 3408        foreach (var i in ids)
 409        {
 1410            var item = _libraryManager.GetItemById<BaseItem>(i, user);
 1411            if (item is null)
 412            {
 1413                return NotFound();
 414            }
 415
 0416            if (user is not null && !item.CanDelete(user))
 417            {
 0418                return Unauthorized("Unauthorized access");
 419            }
 420
 0421            _libraryManager.DeleteItem(
 0422                item,
 0423                new DeleteOptions { DeleteFileLocation = true },
 0424                true);
 425        }
 426
 0427        return NoContent();
 428    }
 429
 430    /// <summary>
 431    /// Get item counts.
 432    /// </summary>
 433    /// <param name="userId">Optional. Get counts from a specific user's library.</param>
 434    /// <param name="isFavorite">Optional. Get counts of favorite items.</param>
 435    /// <response code="200">Item counts returned.</response>
 436    /// <returns>Item counts.</returns>
 437    [HttpGet("Items/Counts")]
 438    [Authorize]
 439    [ProducesResponseType(StatusCodes.Status200OK)]
 440    public ActionResult<ItemCounts> GetItemCounts(
 441        [FromQuery] Guid? userId,
 442        [FromQuery] bool? isFavorite)
 443    {
 0444        userId = RequestHelpers.GetUserId(User, userId);
 0445        var user = userId.IsNullOrEmpty()
 0446            ? null
 0447            : _userManager.GetUserById(userId.Value);
 448
 0449        var query = new InternalItemsQuery(user)
 0450        {
 0451            Recursive = true,
 0452            IsVirtualItem = false,
 0453            IsFavorite = isFavorite,
 0454            DtoOptions = new DtoOptions(false)
 0455            {
 0456                EnableImages = false
 0457            }
 0458        };
 459
 0460        return _libraryManager.GetItemCounts(query);
 461    }
 462
 463    /// <summary>
 464    /// Gets all parents of an item.
 465    /// </summary>
 466    /// <param name="itemId">The item id.</param>
 467    /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
 468    /// <response code="200">Item parents returned.</response>
 469    /// <response code="404">Item not found.</response>
 470    /// <returns>Item parents.</returns>
 471    [HttpGet("Items/{itemId}/Ancestors")]
 472    [Authorize]
 473    [ProducesResponseType(StatusCodes.Status200OK)]
 474    [ProducesResponseType(StatusCodes.Status404NotFound)]
 475    public ActionResult<IEnumerable<BaseItemDto>> GetAncestors([FromRoute, Required] Guid itemId, [FromQuery] Guid? user
 476    {
 1477        userId = RequestHelpers.GetUserId(User, userId);
 1478        var user = userId.IsNullOrEmpty()
 1479            ? null
 1480            : _userManager.GetUserById(userId.Value);
 1481        var item = _libraryManager.GetItemById<BaseItem>(itemId, user);
 1482        if (item is null)
 483        {
 1484            return NotFound();
 485        }
 486
 0487        var baseItemDtos = new List<BaseItemDto>();
 488
 0489        var dtoOptions = new DtoOptions();
 0490        BaseItem? parent = item.GetParent();
 491
 0492        while (parent is not null)
 493        {
 0494            if (user is not null)
 495            {
 0496                parent = TranslateParentItem(parent, user);
 0497                if (parent is null)
 498                {
 499                    break;
 500                }
 501            }
 502
 0503            baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user));
 504
 0505            parent = parent.GetParent();
 506        }
 507
 0508        return baseItemDtos;
 509    }
 510
 511    /// <summary>
 512    /// Gets a list of physical paths from virtual folders.
 513    /// </summary>
 514    /// <response code="200">Physical paths returned.</response>
 515    /// <returns>List of physical paths.</returns>
 516    [HttpGet("Library/PhysicalPaths")]
 517    [Authorize(Policy = Policies.RequiresElevation)]
 518    [ProducesResponseType(StatusCodes.Status200OK)]
 519    public ActionResult<IEnumerable<string>> GetPhysicalPaths()
 520    {
 0521        return Ok(_libraryManager.RootFolder.Children
 0522            .SelectMany(c => c.PhysicalLocations));
 523    }
 524
 525    /// <summary>
 526    /// Gets all user media folders.
 527    /// </summary>
 528    /// <param name="isHidden">Optional. Filter by folders that are marked hidden, or not.</param>
 529    /// <response code="200">Media folders returned.</response>
 530    /// <returns>List of user media folders.</returns>
 531    [HttpGet("Library/MediaFolders")]
 532    [Authorize(Policy = Policies.RequiresElevation)]
 533    [ProducesResponseType(StatusCodes.Status200OK)]
 534    public ActionResult<QueryResult<BaseItemDto>> GetMediaFolders([FromQuery] bool? isHidden)
 535    {
 0536        var items = _libraryManager.GetUserRootFolder().Children
 0537            .Concat(_libraryManager.RootFolder.VirtualChildren)
 0538            .Where(i => _libraryManager.GetLibraryOptions(i).Enabled)
 0539            .OrderBy(i => i.SortName)
 0540            .ToList();
 541
 0542        if (isHidden.HasValue)
 543        {
 0544            var val = isHidden.Value;
 545
 0546            items = items.Where(i => i.IsHidden == val).ToList();
 547        }
 548
 0549        var dtoOptions = new DtoOptions();
 0550        var resultArray = _dtoService.GetBaseItemDtos(items, dtoOptions);
 0551        return new QueryResult<BaseItemDto>(resultArray);
 552    }
 553
 554    /// <summary>
 555    /// Reports that new episodes of a series have been added by an external source.
 556    /// </summary>
 557    /// <param name="tvdbId">The tvdbId.</param>
 558    /// <response code="204">Report success.</response>
 559    /// <returns>A <see cref="NoContentResult"/>.</returns>
 560    [HttpPost("Library/Series/Added", Name = "PostAddedSeries")]
 561    [HttpPost("Library/Series/Updated")]
 562    [Authorize]
 563    [ProducesResponseType(StatusCodes.Status204NoContent)]
 564    public ActionResult PostUpdatedSeries([FromQuery] string? tvdbId)
 565    {
 0566        var series = _libraryManager.GetItemList(new InternalItemsQuery
 0567        {
 0568            IncludeItemTypes = new[] { BaseItemKind.Series },
 0569            DtoOptions = new DtoOptions(false)
 0570            {
 0571                EnableImages = false
 0572            }
 0573        }).Where(i => string.Equals(tvdbId, i.GetProviderId(MediaBrowser.Model.Entities.MetadataProvider.Tvdb), StringCo
 574
 0575        foreach (var item in series)
 576        {
 0577            _libraryMonitor.ReportFileSystemChanged(item.Path);
 578        }
 579
 0580        return NoContent();
 581    }
 582
 583    /// <summary>
 584    /// Reports that new movies have been added by an external source.
 585    /// </summary>
 586    /// <param name="tmdbId">The tmdbId.</param>
 587    /// <param name="imdbId">The imdbId.</param>
 588    /// <response code="204">Report success.</response>
 589    /// <returns>A <see cref="NoContentResult"/>.</returns>
 590    [HttpPost("Library/Movies/Added", Name = "PostAddedMovies")]
 591    [HttpPost("Library/Movies/Updated")]
 592    [Authorize]
 593    [ProducesResponseType(StatusCodes.Status204NoContent)]
 594    public ActionResult PostUpdatedMovies([FromQuery] string? tmdbId, [FromQuery] string? imdbId)
 595    {
 0596        var movies = _libraryManager.GetItemList(new InternalItemsQuery
 0597        {
 0598            IncludeItemTypes = new[] { BaseItemKind.Movie },
 0599            DtoOptions = new DtoOptions(false)
 0600            {
 0601                EnableImages = false
 0602            }
 0603        });
 604
 0605        if (!string.IsNullOrWhiteSpace(imdbId))
 606        {
 0607            movies = movies.Where(i => string.Equals(imdbId, i.GetProviderId(MediaBrowser.Model.Entities.MetadataProvide
 608        }
 0609        else if (!string.IsNullOrWhiteSpace(tmdbId))
 610        {
 0611            movies = movies.Where(i => string.Equals(tmdbId, i.GetProviderId(MediaBrowser.Model.Entities.MetadataProvide
 612        }
 613        else
 614        {
 0615            movies = new List<BaseItem>();
 616        }
 617
 0618        foreach (var item in movies)
 619        {
 0620            _libraryMonitor.ReportFileSystemChanged(item.Path);
 621        }
 622
 0623        return NoContent();
 624    }
 625
 626    /// <summary>
 627    /// Reports that new movies have been added by an external source.
 628    /// </summary>
 629    /// <param name="dto">The update paths.</param>
 630    /// <response code="204">Report success.</response>
 631    /// <returns>A <see cref="NoContentResult"/>.</returns>
 632    [HttpPost("Library/Media/Updated")]
 633    [Authorize]
 634    [ProducesResponseType(StatusCodes.Status204NoContent)]
 635    public ActionResult PostUpdatedMedia([FromBody, Required] MediaUpdateInfoDto dto)
 636    {
 0637        foreach (var item in dto.Updates)
 638        {
 0639            _libraryMonitor.ReportFileSystemChanged(item.Path ?? throw new ArgumentException("Item path can't be null.")
 640        }
 641
 0642        return NoContent();
 643    }
 644
 645    /// <summary>
 646    /// Downloads item media.
 647    /// </summary>
 648    /// <param name="itemId">The item id.</param>
 649    /// <response code="200">Media downloaded.</response>
 650    /// <response code="404">Item not found.</response>
 651    /// <returns>A <see cref="FileResult"/> containing the media stream.</returns>
 652    /// <exception cref="ArgumentException">User can't download or item can't be downloaded.</exception>
 653    [HttpGet("Items/{itemId}/Download")]
 654    [Authorize(Policy = Policies.Download)]
 655    [ProducesResponseType(StatusCodes.Status200OK)]
 656    [ProducesResponseType(StatusCodes.Status404NotFound)]
 657    [ProducesFile("video/*", "audio/*")]
 658    public async Task<ActionResult> GetDownload([FromRoute, Required] Guid itemId)
 659    {
 1660        var userId = User.GetUserId();
 1661        var user = userId.IsEmpty()
 1662            ? null
 1663            : _userManager.GetUserById(userId);
 1664        var item = _libraryManager.GetItemById<BaseItem>(itemId, user);
 1665        if (item is null)
 666        {
 1667            return NotFound();
 668        }
 669
 0670        if (user is not null)
 671        {
 0672            if (!item.CanDownload(user))
 673            {
 0674                throw new ArgumentException("Item does not support downloading");
 675            }
 676        }
 677        else
 678        {
 0679            if (!item.CanDownload())
 680            {
 0681                throw new ArgumentException("Item does not support downloading");
 682            }
 683        }
 684
 0685        if (user is not null)
 686        {
 0687            await LogDownloadAsync(item, user).ConfigureAwait(false);
 688        }
 689
 690        // Quotes are valid in linux. They'll possibly cause issues here.
 0691        var filename = Path.GetFileName(item.Path)?.Replace("\"", string.Empty, StringComparison.Ordinal);
 692
 0693        var filePath = item.Path;
 0694        if (item.IsFileProtocol)
 695        {
 696            // PhysicalFile does not work well with symlinks at the moment.
 0697            var resolved = FileSystemHelper.ResolveLinkTarget(filePath, returnFinalTarget: true);
 0698            if (resolved is not null && resolved.Exists)
 699            {
 0700                filePath = resolved.FullName;
 701            }
 702        }
 703
 0704        return PhysicalFile(filePath, MimeTypes.GetMimeType(filePath), filename, true);
 1705    }
 706
 707    /// <summary>
 708    /// Gets similar items.
 709    /// </summary>
 710    /// <param name="itemId">The item id.</param>
 711    /// <param name="excludeArtistIds">Exclude artist ids.</param>
 712    /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
 713    /// <param name="limit">Optional. The maximum number of records to return.</param>
 714    /// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows mul
 715    /// <param name="cancellationToken">The cancellation token.</param>
 716    /// <response code="200">Similar items returned.</response>
 717    /// <returns>A <see cref="QueryResult{BaseItemDto}"/> containing the similar items.</returns>
 718    [HttpGet("Artists/{itemId}/Similar", Name = "GetSimilarArtists")]
 719    [HttpGet("Items/{itemId}/Similar")]
 720    [HttpGet("Albums/{itemId}/Similar", Name = "GetSimilarAlbums")]
 721    [HttpGet("Shows/{itemId}/Similar", Name = "GetSimilarShows")]
 722    [HttpGet("Movies/{itemId}/Similar", Name = "GetSimilarMovies")]
 723    [HttpGet("Trailers/{itemId}/Similar", Name = "GetSimilarTrailers")]
 724    [Authorize]
 725    [ProducesResponseType(StatusCodes.Status200OK)]
 726    public async Task<ActionResult<QueryResult<BaseItemDto>>> GetSimilarItems(
 727        [FromRoute, Required] Guid itemId,
 728        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] excludeArtistIds,
 729        [FromQuery] Guid? userId,
 730        [FromQuery] int? limit,
 731        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields,
 732        CancellationToken cancellationToken)
 733    {
 6734        userId = RequestHelpers.GetUserId(User, userId);
 6735        var user = userId.IsNullOrEmpty()
 6736            ? null
 6737            : _userManager.GetUserById(userId.Value);
 6738        var item = itemId.IsEmpty()
 6739            ? (user is null
 6740                ? _libraryManager.RootFolder
 6741                : _libraryManager.GetUserRootFolder())
 6742            : _libraryManager.GetItemById<BaseItem>(itemId, user);
 6743        if (item is null)
 744        {
 6745            return NotFound();
 746        }
 747
 0748        if (item is Episode || (item is IItemByName && item is not MusicArtist))
 749        {
 0750            return new QueryResult<BaseItemDto>();
 751        }
 752
 0753        var dtoOptions = new DtoOptions { Fields = fields };
 754
 755        // Get library options for provider configuration
 0756        var libraryOptions = _libraryManager.GetLibraryOptions(item);
 757
 0758        var itemsResult = await _similarItemsManager.GetSimilarItemsAsync(
 0759            item,
 0760            excludeArtistIds,
 0761            user,
 0762            dtoOptions,
 0763            limit,
 0764            libraryOptions,
 0765            cancellationToken).ConfigureAwait(false);
 766
 0767        var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user);
 768
 0769        return new QueryResult<BaseItemDto>(
 0770            0,
 0771            itemsResult.Count,
 0772            returnList);
 6773    }
 774
 775    /// <summary>
 776    /// Gets the library options info.
 777    /// </summary>
 778    /// <param name="libraryContentType">Library content type.</param>
 779    /// <param name="isNewLibrary">Whether this is a new library.</param>
 780    /// <response code="200">Library options info returned.</response>
 781    /// <returns>Library options info.</returns>
 782    [HttpGet("Libraries/AvailableOptions")]
 783    [Authorize(Policy = Policies.FirstTimeSetupOrDefault)]
 784    [ProducesResponseType(StatusCodes.Status200OK)]
 785    public ActionResult<LibraryOptionsResultDto> GetLibraryOptionsInfo(
 786        [FromQuery] CollectionType? libraryContentType,
 787        [FromQuery] bool isNewLibrary = false)
 788    {
 0789        var result = new LibraryOptionsResultDto();
 790
 0791        var types = GetRepresentativeItemTypes(libraryContentType);
 0792        var typesList = types.ToList();
 793
 0794        var plugins = _providerManager.GetAllMetadataPlugins()
 0795            .Where(i => types.Contains(i.ItemType, StringComparison.OrdinalIgnoreCase))
 0796            .OrderBy(i => typesList.IndexOf(i.ItemType))
 0797            .ToList();
 798
 0799        result.MetadataSavers = plugins
 0800            .SelectMany(i => i.Plugins.Where(p => p.Type == MetadataPluginType.MetadataSaver))
 0801            .Select(i => new LibraryOptionInfoDto
 0802            {
 0803                Name = i.Name,
 0804                DefaultEnabled = IsSaverEnabledByDefault(i.Name, types, isNewLibrary)
 0805            })
 0806            .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
 0807            .ToArray();
 808
 0809        result.MetadataReaders = plugins
 0810            .SelectMany(i => i.Plugins.Where(p => p.Type == MetadataPluginType.LocalMetadataProvider))
 0811            .Select(i => new LibraryOptionInfoDto
 0812            {
 0813                Name = i.Name,
 0814                DefaultEnabled = true
 0815            })
 0816            .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
 0817            .ToArray();
 818
 0819        result.SubtitleFetchers = plugins
 0820            .SelectMany(i => i.Plugins.Where(p => p.Type == MetadataPluginType.SubtitleFetcher))
 0821            .Select(i => new LibraryOptionInfoDto
 0822            {
 0823                Name = i.Name,
 0824                DefaultEnabled = true
 0825            })
 0826            .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
 0827            .ToArray();
 828
 0829        result.LyricFetchers = plugins
 0830            .SelectMany(i => i.Plugins.Where(p => p.Type == MetadataPluginType.LyricFetcher))
 0831            .Select(i => new LibraryOptionInfoDto
 0832            {
 0833                Name = i.Name,
 0834                DefaultEnabled = true
 0835            })
 0836            .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
 0837            .ToArray();
 838
 0839        result.MediaSegmentProviders = plugins
 0840            .SelectMany(i => i.Plugins.Where(p => p.Type == MetadataPluginType.MediaSegmentProvider))
 0841            .Select(i => new LibraryOptionInfoDto
 0842            {
 0843                Name = i.Name,
 0844                DefaultEnabled = true
 0845            })
 0846            .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
 0847            .ToArray();
 848
 0849        var typeOptions = new List<LibraryTypeOptionsDto>();
 850
 0851        foreach (var type in types)
 852        {
 0853            TypeOptions.DefaultImageOptions.TryGetValue(type, out var defaultImageOptions);
 854
 0855            typeOptions.Add(new LibraryTypeOptionsDto
 0856            {
 0857                Type = type,
 0858
 0859                MetadataFetchers = plugins
 0860                    .Where(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase))
 0861                    .SelectMany(i => i.Plugins.Where(p => p.Type == MetadataPluginType.MetadataFetcher))
 0862                    .Select(i => new LibraryOptionInfoDto
 0863                    {
 0864                        Name = i.Name,
 0865                        DefaultEnabled = IsMetadataFetcherEnabledByDefault(i.Name, type, isNewLibrary)
 0866                    })
 0867                    .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
 0868                    .ToArray(),
 0869
 0870                ImageFetchers = plugins
 0871                    .Where(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase))
 0872                    .SelectMany(i => i.Plugins.Where(p => p.Type == MetadataPluginType.ImageFetcher))
 0873                    .Select(i => new LibraryOptionInfoDto
 0874                    {
 0875                        Name = i.Name,
 0876                        DefaultEnabled = IsImageFetcherEnabledByDefault(i.Name, type, isNewLibrary)
 0877                    })
 0878                    .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
 0879                    .ToArray(),
 0880
 0881                SimilarItemProviders = plugins
 0882                    .Where(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase))
 0883                    .SelectMany(i => i.Plugins.Where(p => p.Type == MetadataPluginType.LocalSimilarityProvider || p.Type
 0884                    .Select(i => new LibraryOptionInfoDto
 0885                    {
 0886                        Name = i.Name,
 0887                        DefaultEnabled = i.Type == MetadataPluginType.LocalSimilarityProvider
 0888                    })
 0889                    .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
 0890                    .ToArray(),
 0891
 0892                SupportedImageTypes = plugins
 0893                    .Where(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase))
 0894                    .SelectMany(i => i.SupportedImageTypes ?? Array.Empty<ImageType>())
 0895                    .Distinct()
 0896                    .ToArray(),
 0897
 0898                DefaultImageOptions = defaultImageOptions ?? Array.Empty<ImageOption>()
 0899            });
 900        }
 901
 0902        result.TypeOptions = typeOptions.ToArray();
 903
 0904        return result;
 905    }
 906
 907    private BaseItem? TranslateParentItem(BaseItem item, User user)
 908    {
 0909        return item.GetParent() is AggregateFolder
 0910            ? _libraryManager.GetUserRootFolder().GetChildren(user, true)
 0911                .FirstOrDefault(i => i.PhysicalLocations.Contains(item.Path))
 0912            : item;
 913    }
 914
 915    private async Task LogDownloadAsync(BaseItem item, User user)
 916    {
 917        try
 918        {
 0919            await _activityManager.CreateAsync(new ActivityLog(
 0920                string.Format(CultureInfo.InvariantCulture, _localization.GetServerLocalizedString("UserDownloadingItemW
 0921                "UserDownloadingContent",
 0922                User.GetUserId())
 0923            {
 0924                ShortOverview = string.Format(CultureInfo.InvariantCulture, _localization.GetServerLocalizedString("AppD
 0925                ItemId = item.Id.ToString("N", CultureInfo.InvariantCulture)
 0926            }).ConfigureAwait(false);
 0927        }
 0928        catch
 929        {
 930            // Logged at lower levels
 0931        }
 0932    }
 933
 934    private static string[] GetRepresentativeItemTypes(CollectionType? contentType)
 935    {
 0936        return contentType switch
 0937        {
 0938            CollectionType.boxsets => new[] { "BoxSet" },
 0939            CollectionType.playlists => new[] { "Playlist" },
 0940            CollectionType.movies => new[] { "Movie" },
 0941            CollectionType.tvshows => new[] { "Series", "Season", "Episode" },
 0942            CollectionType.books => new[] { "Book", "AudioBook" },
 0943            CollectionType.music => new[] { "MusicArtist", "MusicAlbum", "Audio", "MusicVideo" },
 0944            CollectionType.homevideos => new[] { "Video", "Photo" },
 0945            CollectionType.photos => new[] { "Video", "Photo" },
 0946            CollectionType.musicvideos => new[] { "MusicVideo" },
 0947            _ => new[] { "Series", "Season", "Episode", "Movie" }
 0948        };
 949    }
 950
 951    private bool IsSaverEnabledByDefault(string name, string[] itemTypes, bool isNewLibrary)
 952    {
 0953        if (isNewLibrary)
 954        {
 0955            return false;
 956        }
 957
 0958        var metadataOptions = _serverConfigurationManager.Configuration.MetadataOptions
 0959            .Where(i => itemTypes.Contains(i.ItemType ?? string.Empty, StringComparison.OrdinalIgnoreCase))
 0960            .ToArray();
 961
 0962        return metadataOptions.Length == 0 || metadataOptions.Any(i => !i.DisabledMetadataSavers.Contains(name, StringCo
 963    }
 964
 965    private bool IsMetadataFetcherEnabledByDefault(string name, string type, bool isNewLibrary)
 966    {
 0967        if (isNewLibrary)
 968        {
 0969            if (string.Equals(name, "TheMovieDb", StringComparison.OrdinalIgnoreCase))
 970            {
 0971                return !(string.Equals(type, "Season", StringComparison.OrdinalIgnoreCase)
 0972                         || string.Equals(type, "Episode", StringComparison.OrdinalIgnoreCase)
 0973                         || string.Equals(type, "MusicVideo", StringComparison.OrdinalIgnoreCase));
 974            }
 975
 0976            return string.Equals(name, "TheTVDB", StringComparison.OrdinalIgnoreCase)
 0977                   || string.Equals(name, "TheAudioDB", StringComparison.OrdinalIgnoreCase)
 0978                   || string.Equals(name, "MusicBrainz", StringComparison.OrdinalIgnoreCase);
 979        }
 980
 0981        var metadataOptions = _serverConfigurationManager.GetMetadataOptionsForType(type);
 0982        return metadataOptions is null || !metadataOptions.DisabledMetadataFetchers.Contains(name, StringComparison.Ordi
 983    }
 984
 985    private bool IsImageFetcherEnabledByDefault(string name, string type, bool isNewLibrary)
 986    {
 0987        if (isNewLibrary)
 988        {
 0989            if (string.Equals(name, "TheMovieDb", StringComparison.OrdinalIgnoreCase))
 990            {
 0991                return !string.Equals(type, "Series", StringComparison.OrdinalIgnoreCase)
 0992                       && !string.Equals(type, "Season", StringComparison.OrdinalIgnoreCase)
 0993                       && !string.Equals(type, "Episode", StringComparison.OrdinalIgnoreCase)
 0994                       && !string.Equals(type, "MusicVideo", StringComparison.OrdinalIgnoreCase);
 995            }
 996
 0997            return string.Equals(name, "TheTVDB", StringComparison.OrdinalIgnoreCase)
 0998                   || string.Equals(name, "Screen Grabber", StringComparison.OrdinalIgnoreCase)
 0999                   || string.Equals(name, "TheAudioDB", StringComparison.OrdinalIgnoreCase)
 01000                   || string.Equals(name, "Image Extractor", StringComparison.OrdinalIgnoreCase);
 1001        }
 1002
 01003        var metadataOptions = _serverConfigurationManager.GetMetadataOptionsForType(type);
 01004        return metadataOptions is null || !metadataOptions.DisabledImageFetchers.Contains(name, StringComparison.Ordinal
 1005    }
 1006}

Methods/Properties

.ctor(MediaBrowser.Controller.Providers.IProviderManager,MediaBrowser.Controller.Library.ISimilarItemsManager,MediaBrowser.Controller.Library.ILibraryManager,MediaBrowser.Controller.Library.IUserManager,MediaBrowser.Controller.Dto.IDtoService,MediaBrowser.Model.Activity.IActivityManager,MediaBrowser.Model.Globalization.ILocalizationManager,MediaBrowser.Controller.Library.ILibraryMonitor,Microsoft.Extensions.Logging.ILogger`1<Jellyfin.Api.Controllers.LibraryController>,MediaBrowser.Controller.Configuration.IServerConfigurationManager)
GetFile(System.Guid)
GetThemeSongs(System.Guid,System.Nullable`1<System.Guid>,System.Boolean,Jellyfin.Data.Enums.ItemSortBy[],Jellyfin.Database.Implementations.Enums.SortOrder[])
GetThemeVideos(System.Guid,System.Nullable`1<System.Guid>,System.Boolean,Jellyfin.Data.Enums.ItemSortBy[],Jellyfin.Database.Implementations.Enums.SortOrder[])
GetThemeMedia(System.Guid,System.Nullable`1<System.Guid>,System.Boolean,Jellyfin.Data.Enums.ItemSortBy[],Jellyfin.Database.Implementations.Enums.SortOrder[])
RefreshLibrary()
DeleteItem(System.Guid)
DeleteItems(System.Guid[])
GetItemCounts(System.Nullable`1<System.Guid>,System.Nullable`1<System.Boolean>)
GetAncestors(System.Guid,System.Nullable`1<System.Guid>)
GetPhysicalPaths()
GetMediaFolders(System.Nullable`1<System.Boolean>)
PostUpdatedSeries(System.String)
PostUpdatedMovies(System.String,System.String)
PostUpdatedMedia(Jellyfin.Api.Models.LibraryDtos.MediaUpdateInfoDto)
GetDownload()
GetSimilarItems()
GetLibraryOptionsInfo(System.Nullable`1<Jellyfin.Data.Enums.CollectionType>,System.Boolean)
TranslateParentItem(MediaBrowser.Controller.Entities.BaseItem,Jellyfin.Database.Implementations.Entities.User)
LogDownloadAsync()
GetRepresentativeItemTypes(System.Nullable`1<Jellyfin.Data.Enums.CollectionType>)
IsSaverEnabledByDefault(System.String,System.String[],System.Boolean)
IsMetadataFetcherEnabledByDefault(System.String,System.String,System.Boolean)
IsImageFetcherEnabledByDefault(System.String,System.String,System.Boolean)