< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.Library.Resolvers.PlaylistResolver
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
Line coverage
36%
Covered lines: 17
Uncovered lines: 30
Coverable lines: 47
Total lines: 106
Line coverage: 36.1%
Branch coverage
64%
Covered branches: 9
Total branches: 14
Branch coverage: 64.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 5/6/2026 - 12:15:23 AM Line coverage: 41.6% (15/36) Branch coverage: 66.6% (8/12) Total lines: 827/6/2026 - 12:16:28 AM Line coverage: 40% (16/40) Branch coverage: 66.6% (8/12) Total lines: 928/2/2026 - 12:17:28 AM Line coverage: 36.1% (17/47) Branch coverage: 64.2% (9/14) Total lines: 106 5/6/2026 - 12:15:23 AM Line coverage: 41.6% (15/36) Branch coverage: 66.6% (8/12) Total lines: 827/6/2026 - 12:16:28 AM Line coverage: 40% (16/40) Branch coverage: 66.6% (8/12) Total lines: 928/2/2026 - 12:17:28 AM Line coverage: 36.1% (17/47) Branch coverage: 64.2% (9/14) Total lines: 106

Coverage delta

Coverage delta 4 -4

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
Resolve(...)64.28%851428.57%

File(s)

/srv/git/jellyfin/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs

#LineLine coverage
 1#nullable disable
 2
 3using System;
 4using System.Collections.Generic;
 5using System.IO;
 6using System.Linq;
 7using Emby.Server.Implementations.Playlists;
 8using Jellyfin.Data.Enums;
 9using Jellyfin.Extensions;
 10using MediaBrowser.Controller.Library;
 11using MediaBrowser.Controller.Playlists;
 12using MediaBrowser.Controller.Resolvers;
 13using MediaBrowser.LocalMetadata.Savers;
 14
 15namespace Emby.Server.Implementations.Library.Resolvers
 16{
 17    /// <summary>
 18    /// <see cref="IItemResolver"/> for <see cref="Playlist"/> library items.
 19    /// </summary>
 20    public class PlaylistResolver : GenericFolderResolver<Playlist>
 21    {
 2222        private readonly CollectionType?[] _musicPlaylistCollectionTypes =
 2223        [
 2224            null,
 2225            CollectionType.music
 2226        ];
 27
 28        /// <inheritdoc/>
 29        protected override Playlist Resolve(ItemResolveArgs args)
 30        {
 6131            if (args.IsDirectory)
 32            {
 33                // It's a playlist if the path is a directory with [playlist] in its name
 5134                var filename = Path.GetFileName(Path.TrimEndingDirectorySeparator(args.Path));
 5135                if (string.IsNullOrEmpty(filename))
 36                {
 037                    return null;
 38                }
 39
 5140                if (filename.Contains("[playlist]", StringComparison.OrdinalIgnoreCase))
 41                {
 042                    return new Playlist
 043                    {
 044                        Path = args.Path,
 045                        Name = filename.Replace("[playlist]", string.Empty, StringComparison.OrdinalIgnoreCase).Trim(),
 046                        OpenAccess = true
 047                    };
 48                }
 49
 50                // Anything directly inside the internal playlists folder is a playlist, even when its
 51                // playlist.xml is missing: failing to resolve here makes the library scan treat the
 52                // playlist as deleted from disk and remove it, taking its items with it.
 5153                if (args.Parent is PlaylistsFolder)
 54                {
 055                    return new Playlist
 056                    {
 057                        Path = args.Path,
 058                        Name = filename,
 059                        OpenAccess = true
 060                    };
 61                }
 62
 63                // It's a directory-based playlist if the directory contains a playlist file
 64                IEnumerable<string> filePaths;
 65                try
 66                {
 5167                    filePaths = Directory.EnumerateFiles(args.Path, "*", new EnumerationOptions { IgnoreInaccessible = t
 5168                }
 069                catch (IOException)
 70                {
 071                    return null;
 72                }
 73
 5174                if (filePaths.Any(f => f.EndsWith(PlaylistXmlSaver.DefaultPlaylistFilename, StringComparison.OrdinalIgno
 75                {
 076                    return new Playlist
 077                    {
 078                        Path = args.Path,
 079                        Name = filename,
 080                        OpenAccess = true
 081                    };
 82                }
 83            }
 84
 85            // Check if this is a music playlist file
 86            // It should have the correct collection type and a supported file extension
 1087            else if (_musicPlaylistCollectionTypes.Contains(args.CollectionType))
 88            {
 1089                var extension = Path.GetExtension(args.Path.AsSpan());
 1090                if (Playlist.SupportedExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
 91                {
 092                    return new Playlist
 093                    {
 094                        Path = args.Path,
 095                        Name = Path.GetFileNameWithoutExtension(args.Path),
 096                        IsInMixedFolder = true,
 097                        PlaylistMediaType = MediaType.Audio,
 098                        OpenAccess = true
 099                    };
 100                }
 101            }
 102
 61103            return null;
 0104        }
 105    }
 106}