commit
6715450598
|
@ -8,19 +8,12 @@ using Emby.Naming.Common;
|
||||||
|
|
||||||
namespace Emby.Naming.Audio
|
namespace Emby.Naming.Audio
|
||||||
{
|
{
|
||||||
public class AudioFileParser
|
public static class AudioFileParser
|
||||||
{
|
{
|
||||||
private readonly NamingOptions _options;
|
public static bool IsAudioFile(string path, NamingOptions options)
|
||||||
|
|
||||||
public AudioFileParser(NamingOptions options)
|
|
||||||
{
|
|
||||||
_options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAudioFile(string path)
|
|
||||||
{
|
{
|
||||||
var extension = Path.GetExtension(path) ?? string.Empty;
|
var extension = Path.GetExtension(path) ?? string.Empty;
|
||||||
return _options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
|
return options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Emby.Naming.TV
|
namespace Emby.Naming.TV
|
||||||
{
|
{
|
||||||
|
@ -29,14 +28,14 @@ namespace Emby.Naming.TV
|
||||||
{
|
{
|
||||||
var result = new SeasonPathParserResult();
|
var result = new SeasonPathParserResult();
|
||||||
|
|
||||||
var seasonNumberInfo = GetSeasonNumberFromPath(path, supportSpecialAliases, supportNumericSeasonFolders);
|
var (seasonNumber, isSeasonFolder) = GetSeasonNumberFromPath(path, supportSpecialAliases, supportNumericSeasonFolders);
|
||||||
|
|
||||||
result.SeasonNumber = seasonNumberInfo.seasonNumber;
|
result.SeasonNumber = seasonNumber;
|
||||||
|
|
||||||
if (result.SeasonNumber.HasValue)
|
if (result.SeasonNumber.HasValue)
|
||||||
{
|
{
|
||||||
result.Success = true;
|
result.Success = true;
|
||||||
result.IsSeasonFolder = seasonNumberInfo.isSeasonFolder;
|
result.IsSeasonFolder = isSeasonFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -90,12 +89,10 @@ namespace Emby.Naming.TV
|
||||||
// Look for one of the season folder names
|
// Look for one of the season folder names
|
||||||
foreach (var name in _seasonFolderNames)
|
foreach (var name in _seasonFolderNames)
|
||||||
{
|
{
|
||||||
var index = filename.IndexOf(name, StringComparison.OrdinalIgnoreCase);
|
if (filename.Contains(name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
|
||||||
if (index != -1)
|
|
||||||
{
|
{
|
||||||
var result = GetSeasonNumberFromPathSubstring(filename.Replace(name, " ", StringComparison.OrdinalIgnoreCase));
|
var result = GetSeasonNumberFromPathSubstring(filename.Replace(name, " ", StringComparison.OrdinalIgnoreCase));
|
||||||
if (result.Item1.HasValue)
|
if (result.seasonNumber.HasValue)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -105,25 +102,32 @@ namespace Emby.Naming.TV
|
||||||
}
|
}
|
||||||
|
|
||||||
var parts = filename.Split(new[] { '.', '_', ' ', '-' }, StringSplitOptions.RemoveEmptyEntries);
|
var parts = filename.Split(new[] { '.', '_', ' ', '-' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
var resultNumber = parts.Select(GetSeasonNumberFromPart).FirstOrDefault(i => i.HasValue);
|
for (int i = 0; i < parts.Length; i++)
|
||||||
return (resultNumber, true);
|
{
|
||||||
|
if (TryGetSeasonNumberFromPart(parts[i], out int seasonNumber))
|
||||||
|
{
|
||||||
|
return (seasonNumber, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int? GetSeasonNumberFromPart(string part)
|
return (null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetSeasonNumberFromPart(ReadOnlySpan<char> part, out int seasonNumber)
|
||||||
{
|
{
|
||||||
|
seasonNumber = 0;
|
||||||
if (part.Length < 2 || !part.StartsWith("s", StringComparison.OrdinalIgnoreCase))
|
if (part.Length < 2 || !part.StartsWith("s", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
part = part.Substring(1);
|
if (int.TryParse(part.Slice(1), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
||||||
|
|
||||||
if (int.TryParse(part, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
|
||||||
{
|
{
|
||||||
return value;
|
seasonNumber = value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -131,7 +135,7 @@ namespace Emby.Naming.TV
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <returns>System.Nullable{System.Int32}.</returns>
|
/// <returns>System.Nullable{System.Int32}.</returns>
|
||||||
private static (int? seasonNumber, bool isSeasonFolder) GetSeasonNumberFromPathSubstring(string path)
|
private static (int? seasonNumber, bool isSeasonFolder) GetSeasonNumberFromPathSubstring(ReadOnlySpan<char> path)
|
||||||
{
|
{
|
||||||
var numericStart = -1;
|
var numericStart = -1;
|
||||||
var length = 0;
|
var length = 0;
|
||||||
|
@ -142,7 +146,7 @@ namespace Emby.Naming.TV
|
||||||
// Find out where the numbers start, and then keep going until they end
|
// Find out where the numbers start, and then keep going until they end
|
||||||
for (var i = 0; i < path.Length; i++)
|
for (var i = 0; i < path.Length; i++)
|
||||||
{
|
{
|
||||||
if (char.IsNumber(path, i))
|
if (char.IsNumber(path[i]))
|
||||||
{
|
{
|
||||||
if (!hasOpenParenth)
|
if (!hasOpenParenth)
|
||||||
{
|
{
|
||||||
|
@ -177,7 +181,7 @@ namespace Emby.Naming.TV
|
||||||
return (null, isSeasonFolder);
|
return (null, isSeasonFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int.Parse(path.Substring(numericStart, length), CultureInfo.InvariantCulture), isSeasonFolder);
|
return (int.Parse(path.Slice(numericStart, length), provider: CultureInfo.InvariantCulture), isSeasonFolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace Emby.Naming.Video
|
||||||
|
|
||||||
if (rule.MediaType == MediaType.Audio)
|
if (rule.MediaType == MediaType.Audio)
|
||||||
{
|
{
|
||||||
if (!new AudioFileParser(_options).IsAudioFile(path))
|
if (!AudioFileParser.IsAudioFile(path, _options))
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,7 @@ namespace Emby.Naming.Video
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetRegexInput(FileSystemMetadata file)
|
private static string GetRegexInput(FileSystemMetadata file)
|
||||||
{
|
{
|
||||||
// For directories, dummy up an extension otherwise the expressions will fail
|
// For directories, dummy up an extension otherwise the expressions will fail
|
||||||
var input = !file.IsDirectory
|
var input = !file.IsDirectory
|
||||||
|
@ -204,7 +204,7 @@ namespace Emby.Naming.Video
|
||||||
return Path.GetFileName(input);
|
return Path.GetFileName(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Match FindMatch(FileSystemMetadata input, Regex regex, int offset)
|
private static Match FindMatch(FileSystemMetadata input, Regex regex, int offset)
|
||||||
{
|
{
|
||||||
var regexInput = GetRegexInput(input);
|
var regexInput = GetRegexInput(input);
|
||||||
|
|
||||||
|
|
|
@ -3521,20 +3521,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray();
|
var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray();
|
||||||
if (includeTypes.Length == 1)
|
|
||||||
{
|
|
||||||
whereClauses.Add("type=@type");
|
|
||||||
if (statement != null)
|
|
||||||
{
|
|
||||||
statement.TryBind("@type", includeTypes[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (includeTypes.Length > 1)
|
|
||||||
{
|
|
||||||
var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'"));
|
|
||||||
whereClauses.Add($"type in ({inClause})");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only specify excluded types if no included types are specified
|
// Only specify excluded types if no included types are specified
|
||||||
if (includeTypes.Length == 0)
|
if (includeTypes.Length == 0)
|
||||||
{
|
{
|
||||||
|
@ -3553,6 +3539,19 @@ namespace Emby.Server.Implementations.Data
|
||||||
whereClauses.Add($"type not in ({inClause})");
|
whereClauses.Add($"type not in ({inClause})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (includeTypes.Length == 1)
|
||||||
|
{
|
||||||
|
whereClauses.Add("type=@type");
|
||||||
|
if (statement != null)
|
||||||
|
{
|
||||||
|
statement.TryBind("@type", includeTypes[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (includeTypes.Length > 1)
|
||||||
|
{
|
||||||
|
var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'"));
|
||||||
|
whereClauses.Add($"type in ({inClause})");
|
||||||
|
}
|
||||||
|
|
||||||
if (query.ChannelIds.Length == 1)
|
if (query.ChannelIds.Length == 1)
|
||||||
{
|
{
|
||||||
|
@ -4927,7 +4926,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
// Not crazy about having this all the way down here, but at least it's in one place
|
// Not crazy about having this all the way down here, but at least it's in one place
|
||||||
readonly Dictionary<string, string[]> _types = GetTypeMapDictionary();
|
readonly Dictionary<string, string[]> _types = GetTypeMapDictionary();
|
||||||
|
|
||||||
private IEnumerable<string> MapIncludeItemTypes(string value)
|
private string[] MapIncludeItemTypes(string value)
|
||||||
{
|
{
|
||||||
if (_types.TryGetValue(value, out string[] result))
|
if (_types.TryGetValue(value, out string[] result))
|
||||||
{
|
{
|
||||||
|
@ -5611,32 +5610,32 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
return counts;
|
return counts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Tuple<int, string>> GetItemValuesToSave(BaseItem item, List<string> inheritedTags)
|
private List<(int, string)> GetItemValuesToSave(BaseItem item, List<string> inheritedTags)
|
||||||
{
|
{
|
||||||
var list = new List<Tuple<int, string>>();
|
var list = new List<(int, string)>();
|
||||||
|
|
||||||
if (item is IHasArtist hasArtist)
|
if (item is IHasArtist hasArtist)
|
||||||
{
|
{
|
||||||
list.AddRange(hasArtist.Artists.Select(i => new Tuple<int, string>(0, i)));
|
list.AddRange(hasArtist.Artists.Select(i => (0, i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is IHasAlbumArtist hasAlbumArtist)
|
if (item is IHasAlbumArtist hasAlbumArtist)
|
||||||
{
|
{
|
||||||
list.AddRange(hasAlbumArtist.AlbumArtists.Select(i => new Tuple<int, string>(1, i)));
|
list.AddRange(hasAlbumArtist.AlbumArtists.Select(i => (1, i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
list.AddRange(item.Genres.Select(i => new Tuple<int, string>(2, i)));
|
list.AddRange(item.Genres.Select(i => (2, i)));
|
||||||
list.AddRange(item.Studios.Select(i => new Tuple<int, string>(3, i)));
|
list.AddRange(item.Studios.Select(i => (3, i)));
|
||||||
list.AddRange(item.Tags.Select(i => new Tuple<int, string>(4, i)));
|
list.AddRange(item.Tags.Select(i => (4, i)));
|
||||||
|
|
||||||
// keywords was 5
|
// keywords was 5
|
||||||
|
|
||||||
list.AddRange(inheritedTags.Select(i => new Tuple<int, string>(6, i)));
|
list.AddRange(inheritedTags.Select(i => (6, i)));
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateItemValues(Guid itemId, List<Tuple<int, string>> values, IDatabaseConnection db)
|
private void UpdateItemValues(Guid itemId, List<(int, string)> values, IDatabaseConnection db)
|
||||||
{
|
{
|
||||||
if (itemId.Equals(Guid.Empty))
|
if (itemId.Equals(Guid.Empty))
|
||||||
{
|
{
|
||||||
|
@ -5658,7 +5657,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
InsertItemValues(guidBlob, values, db);
|
InsertItemValues(guidBlob, values, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InsertItemValues(byte[] idBlob, List<Tuple<int, string>> values, IDatabaseConnection db)
|
private void InsertItemValues(byte[] idBlob, List<(int, string)> values, IDatabaseConnection db)
|
||||||
{
|
{
|
||||||
var startIndex = 0;
|
var startIndex = 0;
|
||||||
var limit = 100;
|
var limit = 100;
|
||||||
|
|
|
@ -142,11 +142,10 @@ namespace Emby.Server.Implementations.Devices
|
||||||
|
|
||||||
public QueryResult<DeviceInfo> GetDevices(DeviceQuery query)
|
public QueryResult<DeviceInfo> GetDevices(DeviceQuery query)
|
||||||
{
|
{
|
||||||
var sessions = _authRepo.Get(new AuthenticationInfoQuery
|
IEnumerable<AuthenticationInfo> sessions = _authRepo.Get(new AuthenticationInfoQuery
|
||||||
{
|
{
|
||||||
//UserId = query.UserId
|
//UserId = query.UserId
|
||||||
HasUser = true
|
HasUser = true
|
||||||
|
|
||||||
}).Items;
|
}).Items;
|
||||||
|
|
||||||
// TODO: DeviceQuery doesn't seem to be used from client. Not even Swagger.
|
// TODO: DeviceQuery doesn't seem to be used from client. Not even Swagger.
|
||||||
|
@ -154,23 +153,19 @@ namespace Emby.Server.Implementations.Devices
|
||||||
{
|
{
|
||||||
var val = query.SupportsSync.Value;
|
var val = query.SupportsSync.Value;
|
||||||
|
|
||||||
sessions = sessions.Where(i => GetCapabilities(i.DeviceId).SupportsSync == val).ToArray();
|
sessions = sessions.Where(i => GetCapabilities(i.DeviceId).SupportsSync == val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!query.UserId.Equals(Guid.Empty))
|
if (!query.UserId.Equals(Guid.Empty))
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(query.UserId);
|
var user = _userManager.GetUserById(query.UserId);
|
||||||
|
|
||||||
sessions = sessions.Where(i => CanAccessDevice(user, i.DeviceId)).ToArray();
|
sessions = sessions.Where(i => CanAccessDevice(user, i.DeviceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
var array = sessions.Select(ToDeviceInfo).ToArray();
|
var array = sessions.Select(ToDeviceInfo).ToArray();
|
||||||
|
|
||||||
return new QueryResult<DeviceInfo>
|
return new QueryResult<DeviceInfo>(array);
|
||||||
{
|
|
||||||
Items = array,
|
|
||||||
TotalRecordCount = array.Length
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DeviceInfo ToDeviceInfo(AuthenticationInfo authInfo)
|
private DeviceInfo ToDeviceInfo(AuthenticationInfo authInfo)
|
||||||
|
@ -186,7 +181,7 @@ namespace Emby.Server.Implementations.Devices
|
||||||
LastUserName = authInfo.UserName,
|
LastUserName = authInfo.UserName,
|
||||||
Name = authInfo.DeviceName,
|
Name = authInfo.DeviceName,
|
||||||
DateLastActivity = authInfo.DateLastActivity,
|
DateLastActivity = authInfo.DateLastActivity,
|
||||||
IconUrl = caps == null ? null : caps.IconUrl
|
IconUrl = caps?.IconUrl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1174,7 +1174,6 @@ namespace Emby.Server.Implementations.Library
|
||||||
|
|
||||||
return _fileSystem.GetDirectoryPaths(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath)
|
return _fileSystem.GetDirectoryPaths(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath)
|
||||||
.Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders, refreshQueue))
|
.Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders, refreshQueue))
|
||||||
.OrderBy(i => i.Name)
|
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1406,15 +1405,23 @@ namespace Emby.Server.Implementations.Library
|
||||||
|
|
||||||
private void SetTopParentOrAncestorIds(InternalItemsQuery query)
|
private void SetTopParentOrAncestorIds(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (query.AncestorIds.Length == 0)
|
var ancestorIds = query.AncestorIds;
|
||||||
|
int len = ancestorIds.Length;
|
||||||
|
if (len == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parents = query.AncestorIds.Select(i => GetItemById(i)).ToList();
|
var parents = new BaseItem[len];
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
if (parents.All(i => i is ICollectionFolder || i is UserView))
|
|
||||||
{
|
{
|
||||||
|
parents[i] = GetItemById(ancestorIds[i]);
|
||||||
|
if (!(parents[i] is ICollectionFolder || parents[i] is UserView))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Optimize by querying against top level views
|
// Optimize by querying against top level views
|
||||||
query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
|
query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
|
||||||
query.AncestorIds = Array.Empty<Guid>();
|
query.AncestorIds = Array.Empty<Guid>();
|
||||||
|
@ -1425,7 +1432,6 @@ namespace Emby.Server.Implementations.Library
|
||||||
query.TopParentIds = new[] { Guid.NewGuid() };
|
query.TopParentIds = new[] { Guid.NewGuid() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
|
@ -1585,7 +1591,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
public async Task<IEnumerable<Video>> GetIntros(BaseItem item, User user)
|
public async Task<IEnumerable<Video>> GetIntros(BaseItem item, User user)
|
||||||
{
|
{
|
||||||
var tasks = IntroProviders
|
var tasks = IntroProviders
|
||||||
.OrderBy(i => i.GetType().Name.IndexOf("Default", StringComparison.OrdinalIgnoreCase) == -1 ? 0 : 1)
|
.OrderBy(i => i.GetType().Name.Contains("Default", StringComparison.OrdinalIgnoreCase) ? 1 : 0)
|
||||||
.Take(1)
|
.Take(1)
|
||||||
.Select(i => GetIntros(i, item, user));
|
.Select(i => GetIntros(i, item, user));
|
||||||
|
|
||||||
|
@ -2363,33 +2369,22 @@ namespace Emby.Server.Implementations.Library
|
||||||
new SubtitleResolver(BaseItem.LocalizationManager, _fileSystem).AddExternalSubtitleStreams(streams, videoPath, streams.Count, files);
|
new SubtitleResolver(BaseItem.LocalizationManager, _fileSystem).AddExternalSubtitleStreams(streams, videoPath, streams.Count, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsVideoFile(string path, LibraryOptions libraryOptions)
|
/// <inheritdoc />
|
||||||
|
public bool IsVideoFile(string path)
|
||||||
{
|
{
|
||||||
var resolver = new VideoResolver(GetNamingOptions());
|
var resolver = new VideoResolver(GetNamingOptions());
|
||||||
return resolver.IsVideoFile(path);
|
return resolver.IsVideoFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsVideoFile(string path)
|
/// <inheritdoc />
|
||||||
{
|
|
||||||
return IsVideoFile(path, new LibraryOptions());
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAudioFile(string path, LibraryOptions libraryOptions)
|
|
||||||
{
|
|
||||||
var parser = new AudioFileParser(GetNamingOptions());
|
|
||||||
return parser.IsAudioFile(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAudioFile(string path)
|
public bool IsAudioFile(string path)
|
||||||
{
|
=> AudioFileParser.IsAudioFile(path, GetNamingOptions());
|
||||||
return IsAudioFile(path, new LibraryOptions());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public int? GetSeasonNumberFromPath(string path)
|
public int? GetSeasonNumberFromPath(string path)
|
||||||
{
|
=> SeasonPathParser.Parse(path, true, true).SeasonNumber;
|
||||||
return SeasonPathParser.Parse(path, true, true).SeasonNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh)
|
public bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh)
|
||||||
{
|
{
|
||||||
var series = episode.Series;
|
var series = episode.Series;
|
||||||
|
|
|
@ -73,7 +73,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
{
|
{
|
||||||
// Return audio if the path is a file and has a matching extension
|
// Return audio if the path is a file and has a matching extension
|
||||||
|
|
||||||
var libraryOptions = args.GetLibraryOptions();
|
|
||||||
var collectionType = args.GetCollectionType();
|
var collectionType = args.GetCollectionType();
|
||||||
|
|
||||||
var isBooksCollectionType = string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase);
|
var isBooksCollectionType = string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase);
|
||||||
|
@ -92,7 +91,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
return FindAudio<AudioBook>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
|
return FindAudio<AudioBook>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LibraryManager.IsAudioFile(args.Path, libraryOptions))
|
if (LibraryManager.IsAudioFile(args.Path))
|
||||||
{
|
{
|
||||||
var extension = Path.GetExtension(args.Path);
|
var extension = Path.GetExtension(args.Path);
|
||||||
|
|
||||||
|
@ -105,7 +104,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
var isMixedCollectionType = string.IsNullOrEmpty(collectionType);
|
var isMixedCollectionType = string.IsNullOrEmpty(collectionType);
|
||||||
|
|
||||||
// For conflicting extensions, give priority to videos
|
// For conflicting extensions, give priority to videos
|
||||||
if (isMixedCollectionType && LibraryManager.IsVideoFile(args.Path, libraryOptions))
|
if (isMixedCollectionType && LibraryManager.IsVideoFile(args.Path))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +120,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
{
|
{
|
||||||
item = new MediaBrowser.Controller.Entities.Audio.Audio();
|
item = new MediaBrowser.Controller.Entities.Audio.Audio();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isBooksCollectionType)
|
else if (isBooksCollectionType)
|
||||||
{
|
{
|
||||||
item = new AudioBook();
|
item = new AudioBook();
|
||||||
|
|
|
@ -5,7 +5,6 @@ using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Controller.Resolvers;
|
using MediaBrowser.Controller.Resolvers;
|
||||||
using MediaBrowser.Model.Configuration;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -78,9 +77,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determine if the supplied file data points to a music album.
|
/// Determine if the supplied file data points to a music album.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsMusicAlbum(string path, IDirectoryService directoryService, LibraryOptions libraryOptions)
|
public bool IsMusicAlbum(string path, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, libraryOptions, _libraryManager);
|
return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, _libraryManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -94,7 +93,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
if (args.IsDirectory)
|
if (args.IsDirectory)
|
||||||
{
|
{
|
||||||
// if (args.Parent is MusicArtist) return true; //saves us from testing children twice
|
// if (args.Parent is MusicArtist) return true; //saves us from testing children twice
|
||||||
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, args.GetLibraryOptions(), _libraryManager))
|
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, _libraryManager))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +111,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
IDirectoryService directoryService,
|
IDirectoryService directoryService,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
LibraryOptions libraryOptions,
|
|
||||||
ILibraryManager libraryManager)
|
ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
var discSubfolderCount = 0;
|
var discSubfolderCount = 0;
|
||||||
|
@ -132,7 +130,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
}
|
}
|
||||||
|
|
||||||
var path = fileSystemInfo.FullName;
|
var path = fileSystemInfo.FullName;
|
||||||
var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryOptions, libraryManager);
|
var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager);
|
||||||
|
|
||||||
if (hasMusic)
|
if (hasMusic)
|
||||||
{
|
{
|
||||||
|
@ -153,7 +151,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
{
|
{
|
||||||
var fullName = fileSystemInfo.FullName;
|
var fullName = fileSystemInfo.FullName;
|
||||||
|
|
||||||
if (libraryManager.IsAudioFile(fullName, libraryOptions))
|
if (libraryManager.IsAudioFile(fullName))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,14 +80,17 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid mis-identifying top folders
|
// Avoid mis-identifying top folders
|
||||||
if (args.Parent.IsRoot) return null;
|
if (args.Parent.IsRoot)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var directoryService = args.DirectoryService;
|
var directoryService = args.DirectoryService;
|
||||||
|
|
||||||
var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
|
var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
|
||||||
|
|
||||||
// If we contain an album assume we are an artist folder
|
// If we contain an album assume we are an artist folder
|
||||||
return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService, args.GetLibraryOptions())) ? new MusicArtist() : null;
|
return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService)) ? new MusicArtist() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsBluRayDirectory(child.FullName, filename, args.DirectoryService))
|
if (IsBluRayDirectory(child.FullName, filename, args.DirectoryService))
|
||||||
{
|
{
|
||||||
videoInfo = parser.ResolveDirectory(args.Path);
|
videoInfo = parser.ResolveDirectory(args.Path);
|
||||||
|
@ -137,7 +138,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LibraryManager.IsVideoFile(args.Path, args.GetLibraryOptions()) || videoInfo.IsStub)
|
if (LibraryManager.IsVideoFile(args.Path) || videoInfo.IsStub)
|
||||||
{
|
{
|
||||||
var path = args.Path;
|
var path = args.Path;
|
||||||
|
|
||||||
|
|
|
@ -436,7 +436,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||||
if (result.Items.Count == 1)
|
if (result.Items.Count == 1)
|
||||||
{
|
{
|
||||||
var videoPath = result.Items[0].Path;
|
var videoPath = result.Items[0].Path;
|
||||||
var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(LibraryManager, libraryOptions, videoPath, i.Name));
|
var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(LibraryManager, videoPath, i.Name));
|
||||||
|
|
||||||
if (!hasPhotos)
|
if (!hasPhotos)
|
||||||
{
|
{
|
||||||
|
@ -446,8 +446,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||||
return movie;
|
return movie;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
|
||||||
if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
|
|
||||||
{
|
{
|
||||||
return GetMultiDiscMovie<T>(multiDiscFolders, directoryService);
|
return GetMultiDiscMovie<T>(multiDiscFolders, directoryService);
|
||||||
}
|
}
|
||||||
|
@ -519,14 +518,15 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int additionalPartsLen = folderPaths.Count - 1;
|
||||||
|
var additionalParts = new string[additionalPartsLen];
|
||||||
|
folderPaths.CopyTo(1, additionalParts, 0, additionalPartsLen);
|
||||||
|
|
||||||
var returnVideo = new T
|
var returnVideo = new T
|
||||||
{
|
{
|
||||||
Path = folderPaths[0],
|
Path = folderPaths[0],
|
||||||
|
AdditionalParts = additionalParts,
|
||||||
AdditionalParts = folderPaths.Skip(1).ToArray(),
|
|
||||||
|
|
||||||
VideoType = videoTypes[0],
|
VideoType = videoTypes[0],
|
||||||
|
|
||||||
Name = result[0].Name
|
Name = result[0].Name
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -63,13 +63,12 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||||
{
|
{
|
||||||
if (!file.IsDirectory && PhotoResolver.IsImageFile(file.FullName, _imageProcessor))
|
if (!file.IsDirectory && PhotoResolver.IsImageFile(file.FullName, _imageProcessor))
|
||||||
{
|
{
|
||||||
var libraryOptions = args.GetLibraryOptions();
|
|
||||||
var filename = file.Name;
|
var filename = file.Name;
|
||||||
var ownedByMedia = false;
|
var ownedByMedia = false;
|
||||||
|
|
||||||
foreach (var siblingFile in files)
|
foreach (var siblingFile in files)
|
||||||
{
|
{
|
||||||
if (PhotoResolver.IsOwnedByMedia(_libraryManager, libraryOptions, siblingFile.FullName, filename))
|
if (PhotoResolver.IsOwnedByMedia(_libraryManager, siblingFile.FullName, filename))
|
||||||
{
|
{
|
||||||
ownedByMedia = true;
|
ownedByMedia = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -8,7 +8,6 @@ using System.Linq;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Configuration;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Library.Resolvers
|
namespace Emby.Server.Implementations.Library.Resolvers
|
||||||
|
@ -57,11 +56,10 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||||
|
|
||||||
// Make sure the image doesn't belong to a video file
|
// Make sure the image doesn't belong to a video file
|
||||||
var files = args.DirectoryService.GetFiles(Path.GetDirectoryName(args.Path));
|
var files = args.DirectoryService.GetFiles(Path.GetDirectoryName(args.Path));
|
||||||
var libraryOptions = args.GetLibraryOptions();
|
|
||||||
|
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
if (IsOwnedByMedia(_libraryManager, libraryOptions, file.FullName, filename))
|
if (IsOwnedByMedia(_libraryManager, file.FullName, filename))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -78,17 +76,17 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool IsOwnedByMedia(ILibraryManager libraryManager, LibraryOptions libraryOptions, string file, string imageFilename)
|
internal static bool IsOwnedByMedia(ILibraryManager libraryManager, string file, string imageFilename)
|
||||||
{
|
{
|
||||||
if (libraryManager.IsVideoFile(file, libraryOptions))
|
if (libraryManager.IsVideoFile(file))
|
||||||
{
|
{
|
||||||
return IsOwnedByResolvedMedia(libraryManager, libraryOptions, file, imageFilename);
|
return IsOwnedByResolvedMedia(libraryManager, file, imageFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool IsOwnedByResolvedMedia(ILibraryManager libraryManager, LibraryOptions libraryOptions, string file, string imageFilename)
|
internal static bool IsOwnedByResolvedMedia(ILibraryManager libraryManager, string file, string imageFilename)
|
||||||
=> imageFilename.StartsWith(Path.GetFileNameWithoutExtension(file), StringComparison.OrdinalIgnoreCase);
|
=> imageFilename.StartsWith(Path.GetFileNameWithoutExtension(file), StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
internal static bool IsImageFile(string path, IImageProcessor imageProcessor)
|
internal static bool IsImageFile(string path, IImageProcessor imageProcessor)
|
||||||
|
|
|
@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, args.GetLibraryOptions(), false))
|
if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, false))
|
||||||
{
|
{
|
||||||
return new Series
|
return new Series
|
||||||
{
|
{
|
||||||
|
@ -123,24 +123,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
LibraryOptions libraryOptions,
|
|
||||||
bool isTvContentType)
|
bool isTvContentType)
|
||||||
{
|
{
|
||||||
foreach (var child in fileSystemChildren)
|
foreach (var child in fileSystemChildren)
|
||||||
{
|
{
|
||||||
//if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
|
|
||||||
//{
|
|
||||||
// //logger.LogDebug("Igoring series file or folder marked hidden: {0}", child.FullName);
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Can't enforce this because files saved by Bitcasa are always marked System
|
|
||||||
//if ((attributes & FileAttributes.System) == FileAttributes.System)
|
|
||||||
//{
|
|
||||||
// logger.LogDebug("Igoring series subfolder marked system: {0}", child.FullName);
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (child.IsDirectory)
|
if (child.IsDirectory)
|
||||||
{
|
{
|
||||||
if (IsSeasonFolder(child.FullName, isTvContentType, libraryManager))
|
if (IsSeasonFolder(child.FullName, isTvContentType, libraryManager))
|
||||||
|
@ -152,7 +138,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string fullName = child.FullName;
|
string fullName = child.FullName;
|
||||||
if (libraryManager.IsVideoFile(fullName, libraryOptions))
|
if (libraryManager.IsVideoFile(fullName))
|
||||||
{
|
{
|
||||||
if (isTvContentType)
|
if (isTvContentType)
|
||||||
{
|
{
|
||||||
|
|
|
@ -157,7 +157,8 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <param name="introProviders">The intro providers.</param>
|
/// <param name="introProviders">The intro providers.</param>
|
||||||
/// <param name="itemComparers">The item comparers.</param>
|
/// <param name="itemComparers">The item comparers.</param>
|
||||||
/// <param name="postscanTasks">The postscan tasks.</param>
|
/// <param name="postscanTasks">The postscan tasks.</param>
|
||||||
void AddParts(IEnumerable<IResolverIgnoreRule> rules,
|
void AddParts(
|
||||||
|
IEnumerable<IResolverIgnoreRule> rules,
|
||||||
IEnumerable<IItemResolver> resolvers,
|
IEnumerable<IItemResolver> resolvers,
|
||||||
IEnumerable<IIntroProvider> introProviders,
|
IEnumerable<IIntroProvider> introProviders,
|
||||||
IEnumerable<IBaseItemComparer> itemComparers,
|
IEnumerable<IBaseItemComparer> itemComparers,
|
||||||
|
@ -349,9 +350,6 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <returns><c>true</c> if [is audio file] [the specified path]; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if [is audio file] [the specified path]; otherwise, <c>false</c>.</returns>
|
||||||
bool IsAudioFile(string path);
|
bool IsAudioFile(string path);
|
||||||
|
|
||||||
bool IsAudioFile(string path, LibraryOptions libraryOptions);
|
|
||||||
bool IsVideoFile(string path, LibraryOptions libraryOptions);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the season number from path.
|
/// Gets the season number from path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -30,5 +30,11 @@ namespace MediaBrowser.Model.Querying
|
||||||
{
|
{
|
||||||
Items = Array.Empty<T>();
|
Items = Array.Empty<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public QueryResult(IReadOnlyList<T> items)
|
||||||
|
{
|
||||||
|
Items = items;
|
||||||
|
TotalRecordCount = items.Count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user