Merge pull request #2497 from mark-monteiro/1914-prevent-duplicates-in-playlists
Check for duplicates when adding items to a playlist
This commit is contained in:
commit
7aec11d621
|
@ -91,6 +91,7 @@
|
||||||
- [samuel9554](https://github.com/samuel9554)
|
- [samuel9554](https://github.com/samuel9554)
|
||||||
- [scheidleon](https://github.com/scheidleon)
|
- [scheidleon](https://github.com/scheidleon)
|
||||||
- [sebPomme](https://github.com/sebPomme)
|
- [sebPomme](https://github.com/sebPomme)
|
||||||
|
- [SegiH](https://github.com/SegiH)
|
||||||
- [SenorSmartyPants](https://github.com/SenorSmartyPants)
|
- [SenorSmartyPants](https://github.com/SenorSmartyPants)
|
||||||
- [shemanaev](https://github.com/shemanaev)
|
- [shemanaev](https://github.com/shemanaev)
|
||||||
- [skaro13](https://github.com/skaro13)
|
- [skaro13](https://github.com/skaro13)
|
||||||
|
|
|
@ -9,7 +9,8 @@ namespace Emby.Server.Implementations
|
||||||
{
|
{
|
||||||
{ "HttpListenerHost:DefaultRedirectPath", "web/index.html" },
|
{ "HttpListenerHost:DefaultRedirectPath", "web/index.html" },
|
||||||
{ FfmpegProbeSizeKey, "1G" },
|
{ FfmpegProbeSizeKey, "1G" },
|
||||||
{ FfmpegAnalyzeDurationKey, "200M" }
|
{ FfmpegAnalyzeDurationKey, "200M" },
|
||||||
|
{ PlaylistsAllowDuplicatesKey, bool.TrueString }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,14 @@ using System.Threading.Tasks;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
using MediaBrowser.Controller.Extensions;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Playlists;
|
using MediaBrowser.Controller.Playlists;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Playlists;
|
using MediaBrowser.Model.Playlists;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using PlaylistsNET.Content;
|
using PlaylistsNET.Content;
|
||||||
using PlaylistsNET.Models;
|
using PlaylistsNET.Models;
|
||||||
|
@ -28,6 +30,7 @@ namespace Emby.Server.Implementations.Playlists
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IProviderManager _providerManager;
|
private readonly IProviderManager _providerManager;
|
||||||
|
private readonly IConfiguration _appConfig;
|
||||||
|
|
||||||
public PlaylistManager(
|
public PlaylistManager(
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
|
@ -35,7 +38,8 @@ namespace Emby.Server.Implementations.Playlists
|
||||||
ILibraryMonitor iLibraryMonitor,
|
ILibraryMonitor iLibraryMonitor,
|
||||||
ILogger<PlaylistManager> logger,
|
ILogger<PlaylistManager> logger,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
IProviderManager providerManager)
|
IProviderManager providerManager,
|
||||||
|
IConfiguration appConfig)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
|
@ -43,6 +47,7 @@ namespace Emby.Server.Implementations.Playlists
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_providerManager = providerManager;
|
_providerManager = providerManager;
|
||||||
|
_appConfig = appConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Playlist> GetPlaylists(Guid userId)
|
public IEnumerable<Playlist> GetPlaylists(Guid userId)
|
||||||
|
@ -177,7 +182,7 @@ namespace Emby.Server.Implementations.Playlists
|
||||||
return Playlist.GetPlaylistItems(playlistMediaType, items, user, options);
|
return Playlist.GetPlaylistItems(playlistMediaType, items, user, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddToPlaylist(string playlistId, IEnumerable<Guid> itemIds, Guid userId)
|
public void AddToPlaylist(string playlistId, ICollection<Guid> itemIds, Guid userId)
|
||||||
{
|
{
|
||||||
var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId);
|
var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId);
|
||||||
|
|
||||||
|
@ -187,37 +192,59 @@ namespace Emby.Server.Implementations.Playlists
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddToPlaylistInternal(string playlistId, IEnumerable<Guid> itemIds, User user, DtoOptions options)
|
private void AddToPlaylistInternal(string playlistId, ICollection<Guid> newItemIds, User user, DtoOptions options)
|
||||||
{
|
{
|
||||||
var playlist = _libraryManager.GetItemById(playlistId) as Playlist;
|
// Retrieve the existing playlist
|
||||||
|
var playlist = _libraryManager.GetItemById(playlistId) as Playlist
|
||||||
|
?? throw new ArgumentException("No Playlist exists with Id " + playlistId);
|
||||||
|
|
||||||
if (playlist == null)
|
// Retrieve all the items to be added to the playlist
|
||||||
|
var newItems = GetPlaylistItems(newItemIds, playlist.MediaType, user, options)
|
||||||
|
.Where(i => i.SupportsAddingToPlaylist);
|
||||||
|
|
||||||
|
// Filter out duplicate items, if necessary
|
||||||
|
if (!_appConfig.DoPlaylistsAllowDuplicates())
|
||||||
{
|
{
|
||||||
throw new ArgumentException("No Playlist exists with the supplied Id");
|
var existingIds = playlist.LinkedChildren.Select(c => c.ItemId).ToHashSet();
|
||||||
|
newItems = newItems
|
||||||
|
.Where(i => !existingIds.Contains(i.Id))
|
||||||
|
.Distinct();
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<LinkedChild>();
|
// Create a list of the new linked children to add to the playlist
|
||||||
|
var childrenToAdd = newItems
|
||||||
var items = GetPlaylistItems(itemIds, playlist.MediaType, user, options)
|
.Select(i => LinkedChild.Create(i))
|
||||||
.Where(i => i.SupportsAddingToPlaylist)
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
foreach (var item in items)
|
// Log duplicates that have been ignored, if any
|
||||||
|
int numDuplicates = newItemIds.Count - childrenToAdd.Count;
|
||||||
|
if (numDuplicates > 0)
|
||||||
{
|
{
|
||||||
list.Add(LinkedChild.Create(item));
|
_logger.LogWarning("Ignored adding {DuplicateCount} duplicate items to playlist {PlaylistName}.", numDuplicates, playlist.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var newList = playlist.LinkedChildren.ToList();
|
// Do nothing else if there are no items to add to the playlist
|
||||||
newList.AddRange(list);
|
if (childrenToAdd.Count == 0)
|
||||||
playlist.LinkedChildren = newList.ToArray();
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new array with the updated playlist items
|
||||||
|
var newLinkedChildren = new LinkedChild[playlist.LinkedChildren.Length + childrenToAdd.Count];
|
||||||
|
playlist.LinkedChildren.CopyTo(newLinkedChildren, 0);
|
||||||
|
childrenToAdd.CopyTo(newLinkedChildren, playlist.LinkedChildren.Length);
|
||||||
|
|
||||||
|
// Update the playlist in the repository
|
||||||
|
playlist.LinkedChildren = newLinkedChildren;
|
||||||
playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
|
playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
|
||||||
|
|
||||||
|
// Update the playlist on disk
|
||||||
if (playlist.IsFile)
|
if (playlist.IsFile)
|
||||||
{
|
{
|
||||||
SavePlaylistFile(playlist);
|
SavePlaylistFile(playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refresh playlist metadata
|
||||||
_providerManager.QueueRefresh(
|
_providerManager.QueueRefresh(
|
||||||
playlist.Id,
|
playlist.Id,
|
||||||
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||||
|
|
|
@ -13,24 +13,37 @@ namespace MediaBrowser.Controller.Extensions
|
||||||
public const string FfmpegProbeSizeKey = "FFmpeg:probesize";
|
public const string FfmpegProbeSizeKey = "FFmpeg:probesize";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The key for the FFmpeg analyse duration option.
|
/// The key for the FFmpeg analyze duration option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string FfmpegAnalyzeDurationKey = "FFmpeg:analyzeduration";
|
public const string FfmpegAnalyzeDurationKey = "FFmpeg:analyzeduration";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the FFmpeg probe size from the <see cref="IConfiguration" />.
|
/// The key for a setting that indicates whether playlists should allow duplicate entries.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="configuration">This configuration.</param>
|
public const string PlaylistsAllowDuplicatesKey = "playlists:allowDuplicates";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the FFmpeg probe size from the <see cref="IConfiguration" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration">The configuration to read the setting from.</param>
|
||||||
/// <returns>The FFmpeg probe size option.</returns>
|
/// <returns>The FFmpeg probe size option.</returns>
|
||||||
public static string GetFFmpegProbeSize(this IConfiguration configuration)
|
public static string GetFFmpegProbeSize(this IConfiguration configuration)
|
||||||
=> configuration[FfmpegProbeSizeKey];
|
=> configuration[FfmpegProbeSizeKey];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the FFmpeg analyse duration from the <see cref="IConfiguration" />.
|
/// Gets the FFmpeg analyze duration from the <see cref="IConfiguration" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="configuration">This configuration.</param>
|
/// <param name="configuration">The configuration to read the setting from.</param>
|
||||||
/// <returns>The FFmpeg analyse duration option.</returns>
|
/// <returns>The FFmpeg analyze duration option.</returns>
|
||||||
public static string GetFFmpegAnalyzeDuration(this IConfiguration configuration)
|
public static string GetFFmpegAnalyzeDuration(this IConfiguration configuration)
|
||||||
=> configuration[FfmpegAnalyzeDurationKey];
|
=> configuration[FfmpegAnalyzeDurationKey];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether playlists should allow duplicate entries from the <see cref="IConfiguration"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration">The configuration to read the setting from.</param>
|
||||||
|
/// <returns>True if playlists should allow duplicates, otherwise false.</returns>
|
||||||
|
public static bool DoPlaylistsAllowDuplicates(this IConfiguration configuration)
|
||||||
|
=> configuration.GetValue<bool>(PlaylistsAllowDuplicatesKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Playlists
|
||||||
/// <param name="itemIds">The item ids.</param>
|
/// <param name="itemIds">The item ids.</param>
|
||||||
/// <param name="userId">The user identifier.</param>
|
/// <param name="userId">The user identifier.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
void AddToPlaylist(string playlistId, IEnumerable<Guid> itemIds, Guid userId);
|
void AddToPlaylist(string playlistId, ICollection<Guid> itemIds, Guid userId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes from playlist.
|
/// Removes from playlist.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user