feat: add smart collections to backend.
This commit is contained in:
parent
dcdee2403c
commit
f5448e8a51
8 changed files with 326 additions and 57 deletions
|
@ -1,5 +1,4 @@
|
|||
using MediaBrowser.Model.Plugins;
|
||||
using MediaBrowser.Controller;
|
||||
|
||||
namespace Jellyfin.Plugin.SmartPlaylist {
|
||||
public class PluginConfiguration : BasePluginConfiguration {
|
||||
|
@ -43,7 +42,7 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
(define find-parent (lambda (typename) (invoke-generic *item* "FindParent" nil (list typename))))
|
||||
(define find-artist (lambda nil (find-parent "MediaBrowser.Controller.Entities.Audio.MusicArtist, MediaBrowser.Controller"))))
|
||||
""";
|
||||
store = new Store(new SmartPlaylistFileSystem(Plugin.Instance.ServerApplicationPaths));
|
||||
store = new Store(new SmartFileSystem(Plugin.Instance.ServerApplicationPaths));
|
||||
}
|
||||
private Store store { get; set; }
|
||||
public string InitialProgram { get; set; }
|
||||
|
@ -62,6 +61,21 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
}
|
||||
}
|
||||
}
|
||||
public SmartCollectionDto[] Collections {
|
||||
get {
|
||||
return store.GetAllSmartCollectionsAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
set {
|
||||
var existing = store.GetAllSmartCollectionsAsync().GetAwaiter().GetResult().Select(x => x.Id).ToList();
|
||||
foreach (var p in value) {
|
||||
existing.Remove(p.Id);
|
||||
store.SaveSmartCollectionAsync(p).GetAwaiter().GetResult();
|
||||
}
|
||||
foreach (var p in existing) {
|
||||
store.DeleteSmartCollectionById(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
public object[][] Users {
|
||||
get {
|
||||
return Plugin.Instance.UserManager.Users.Select(x => new object[]{x.Id, x.Username}).ToArray();
|
||||
|
|
84
Jellyfin.Plugin.SmartPlaylist/ScheduledTasks/Common.cs
Normal file
84
Jellyfin.Plugin.SmartPlaylist/ScheduledTasks/Common.cs
Normal file
|
@ -0,0 +1,84 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
using Jellyfin.Plugin.SmartPlaylist.Lisp;
|
||||
using Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler;
|
||||
|
||||
namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
|
||||
|
||||
public class Common {
|
||||
public static readonly BaseItemKind[] AvailableFilterItems = {
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.Playlist,
|
||||
};
|
||||
|
||||
|
||||
public readonly ILogger _logger;
|
||||
public Common(ILogger logger) {
|
||||
_logger = logger;
|
||||
}
|
||||
public Executor SetupExecutor() {
|
||||
var env = new DefaultEnvironment();
|
||||
var executor = new Executor(env);
|
||||
executor.builtins["logd"] = (x) => {
|
||||
_logger.LogDebug(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
|
||||
return Lisp.Boolean.TRUE;
|
||||
};
|
||||
executor.builtins["logi"] = (x) => {
|
||||
_logger.LogInformation(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
|
||||
return Lisp.Boolean.TRUE;
|
||||
};
|
||||
executor.builtins["logw"] = (x) => {
|
||||
_logger.LogWarning(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
|
||||
return Lisp.Boolean.TRUE;
|
||||
};
|
||||
executor.builtins["loge"] = (x) => {
|
||||
_logger.LogError(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
|
||||
return Lisp.Boolean.TRUE;
|
||||
};
|
||||
if (Plugin.Instance is not null) {
|
||||
executor.eval(Plugin.Instance.Configuration.InitialProgram);
|
||||
} else {
|
||||
throw new ApplicationException("Plugin Instance is not yet initialized");
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
public IEnumerable<Guid> FilterCollectionItems(IEnumerable<BaseItem> items, User? user, string name, string program, string sortProgram) {
|
||||
List<BaseItem> results = new List<BaseItem>();
|
||||
Expression expression = new Parser(StringTokenStream.generate(program)).parse(); // parse here, so that we don't repeat the work for each item
|
||||
Executor executor = SetupExecutor();
|
||||
|
||||
executor.environment.Set("*user*", Lisp.Object.FromBase(user));
|
||||
foreach (var i in items) {
|
||||
executor.environment.Set("*item*", Lisp.Object.FromBase(i));
|
||||
var r = executor.eval(expression);
|
||||
_logger.LogTrace("Item {0} evaluated to {1}", i, r.ToString());
|
||||
if ((r is not Lisp.Boolean r_bool) || (r_bool.Value())) {
|
||||
_logger.LogDebug("Added '{0}' to Smart Collection {1}", i, name);
|
||||
results.Add(i);
|
||||
}
|
||||
}
|
||||
executor = SetupExecutor();
|
||||
executor.environment.Set("*user*", Lisp.Object.FromBase(user));
|
||||
executor.environment.Set("*items*", Lisp.Object.FromBase(results));
|
||||
results = new List<BaseItem>();
|
||||
var sort_result = executor.eval(sortProgram);
|
||||
if (sort_result is Cons sorted_items) {
|
||||
foreach (var i in sorted_items.ToList()) {
|
||||
if (i is Lisp.Object iObject && iObject.Value() is BaseItem iBaseItem) {
|
||||
results.Add(iBaseItem);
|
||||
continue;
|
||||
}
|
||||
throw new ApplicationException($"Returned sorted list does contain unexpected items, got {i}");
|
||||
}
|
||||
} else if (sort_result == Lisp.Boolean.FALSE) {
|
||||
} else {
|
||||
throw new ApplicationException($"Did not return a list of items, returned {sort_result}");
|
||||
}
|
||||
return results.Select(x => x.Id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
using System.Globalization;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Model.Collections;
|
||||
|
||||
|
||||
namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
|
||||
public class GenerateCollection: Common, IScheduledTask {
|
||||
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IProviderManager _providerManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ICollectionManager _collectionManager;
|
||||
|
||||
private readonly IStore _store;
|
||||
|
||||
public GenerateCollection(
|
||||
ILogger<Plugin> logger,
|
||||
ILibraryManager libraryManager,
|
||||
IUserManager userManager,
|
||||
IProviderManager providerManager,
|
||||
IFileSystem fileSystem,
|
||||
ICollectionManager collectionManager,
|
||||
IServerApplicationPaths serverApplicationPaths
|
||||
) : base(logger) {
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_providerManager = providerManager;
|
||||
_fileSystem = fileSystem;
|
||||
_collectionManager = collectionManager;
|
||||
|
||||
_store = new Store(new SmartFileSystem(serverApplicationPaths));
|
||||
}
|
||||
|
||||
public string Category => "Library";
|
||||
public string Name => "(re)generate Smart Collections";
|
||||
public string Description => "Generate or regenerate all Smart Collections";
|
||||
public string Key => nameof(GenerateCollection);
|
||||
|
||||
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() {
|
||||
return new[] {
|
||||
new TaskTriggerInfo {
|
||||
IntervalTicks = TimeSpan.FromHours(24).Ticks,
|
||||
Type = TaskTriggerInfo.TriggerInterval,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<CollectionId> CreateNewCollection(string name) {
|
||||
_logger.LogDebug("Creating collection '{0}'", name);
|
||||
return (await _collectionManager.CreateCollectionAsync(
|
||||
new CollectionCreationOptions {
|
||||
Name = name,
|
||||
}
|
||||
)).Id;
|
||||
}
|
||||
|
||||
private IEnumerable<BaseItem> GetAllMedia() {
|
||||
var req = new InternalItemsQuery() {
|
||||
IncludeItemTypes = AvailableFilterItems,
|
||||
Recursive = true,
|
||||
};
|
||||
return _libraryManager.GetItemsResult(req).Items;
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) {
|
||||
_logger.LogInformation("Started regenerate Smart Collections");
|
||||
_logger.LogDebug("Loaded Assemblies:");
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
|
||||
_logger.LogDebug("- {0}", asm);
|
||||
}
|
||||
var i = 0;
|
||||
var smartCollections = await _store.GetAllSmartCollectionsAsync();
|
||||
foreach (SmartCollectionDto dto in smartCollections) {
|
||||
if (!dto.Enabled) {
|
||||
progress.Report(100 * ((double)i)/smartCollections.Count());
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (dto.CollectionId == Guid.Empty) {
|
||||
dto.CollectionId = await CreateNewCollection(dto.Name);
|
||||
_store.DeleteSmartCollection(dto); // delete in case the file was not the canonical one.
|
||||
await _store.SaveSmartCollectionAsync(dto);
|
||||
}
|
||||
var insertItems = FilterCollectionItems(GetAllMedia(), null, dto.Name, dto.Program, dto.SortProgram).ToArray();
|
||||
await ClearCollection(dto.CollectionId);
|
||||
await _collectionManager.AddToCollectionAsync(dto.CollectionId, insertItems);
|
||||
i += 1;
|
||||
progress.Report(100 * ((double)i)/smartCollections.Count());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ClearCollection(CollectionId collectionId) {
|
||||
// fuck if I know
|
||||
if (_libraryManager.GetItemById(collectionId) is not BoxSet collection) {
|
||||
throw new ArgumentException("");
|
||||
}
|
||||
var existingItems = collection.Children;
|
||||
await _collectionManager.RemoveFromCollectionAsync(collectionId, existingItems.Select(x => x.Id));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,15 +19,8 @@ using Lisp_Boolean = Jellyfin.Plugin.SmartPlaylist.Lisp.Boolean;
|
|||
|
||||
|
||||
namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
|
||||
public class GeneratePlaylist : IScheduledTask {
|
||||
public class GeneratePlaylist : Common, IScheduledTask {
|
||||
|
||||
public static readonly BaseItemKind[] AvailableFilterItems = {
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.Playlist,
|
||||
};
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
@ -44,15 +37,14 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
|
|||
IFileSystem fileSystem,
|
||||
IPlaylistManager playlistManager,
|
||||
IServerApplicationPaths serverApplicationPaths
|
||||
) {
|
||||
_logger = logger;
|
||||
) : base(logger) {
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_providerManager = providerManager;
|
||||
_fileSystem = fileSystem;
|
||||
_playlistManager = playlistManager;
|
||||
|
||||
_store = new Store(new SmartPlaylistFileSystem(serverApplicationPaths));
|
||||
_store = new Store(new SmartFileSystem(serverApplicationPaths));
|
||||
}
|
||||
|
||||
public string Category => "Library";
|
||||
|
@ -81,33 +73,6 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
|
|||
return playlistGuid;
|
||||
}
|
||||
|
||||
private Executor SetupExecutor() {
|
||||
var env = new DefaultEnvironment();
|
||||
var executor = new Executor(env);
|
||||
executor.builtins["logd"] = (x) => {
|
||||
_logger.LogDebug(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
|
||||
return Lisp_Boolean.TRUE;
|
||||
};
|
||||
executor.builtins["logi"] = (x) => {
|
||||
_logger.LogInformation(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
|
||||
return Lisp_Boolean.TRUE;
|
||||
};
|
||||
executor.builtins["logw"] = (x) => {
|
||||
_logger.LogWarning(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
|
||||
return Lisp_Boolean.TRUE;
|
||||
};
|
||||
executor.builtins["loge"] = (x) => {
|
||||
_logger.LogError(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
|
||||
return Lisp_Boolean.TRUE;
|
||||
};
|
||||
if (Plugin.Instance is not null) {
|
||||
executor.eval(Plugin.Instance.Configuration.InitialProgram);
|
||||
} else {
|
||||
throw new ApplicationException("Plugin Instance is not yet initialized");
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
|
||||
private IEnumerable<Guid> FilterPlaylistItems(IEnumerable<BaseItem> items, User user, SmartPlaylistDto smartPlaylist) {
|
||||
List<BaseItem> results = new List<BaseItem>();
|
||||
Expression expression = new Parser(StringTokenStream.generate(smartPlaylist.Program)).parse(); // parse here, so that we don't repeat the work for each item
|
||||
|
@ -162,6 +127,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
|
|||
foreach (SmartPlaylistDto dto in all_playlists) {
|
||||
if (!dto.Enabled) {
|
||||
i += 1;
|
||||
progress.Report(100 * ((double)i)/all_playlists.Count());
|
||||
continue;
|
||||
}
|
||||
var changedDto = false;
|
||||
|
|
|
@ -108,4 +108,15 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
info.AddValue("Enabled", Enabled);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SmartCollectionDto {
|
||||
public SmartCollectionId Id { get; set; }
|
||||
public CollectionId CollectionId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Program { get; set; }
|
||||
public string SortProgram { get; set; }
|
||||
public string? Filename { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
}
|
|
@ -3,34 +3,61 @@ using MediaBrowser.Controller;
|
|||
namespace Jellyfin.Plugin.SmartPlaylist {
|
||||
|
||||
public interface ISmartPlaylistFileSystem {
|
||||
public string StoragePath { get; }
|
||||
public string GetSmartPlaylistFilePath(SmartPlaylistId smartPlaylistId);
|
||||
public string FindSmartPlaylistFilePath(SmartPlaylistId smartPlaylistId);
|
||||
public string PlaylistStoragePath { get; }
|
||||
public string CollectionStoragePath { get; }
|
||||
|
||||
public string GetSmartPlaylistFilePath(string id);
|
||||
public string FindSmartPlaylistFilePath(string id);
|
||||
public string[] FindAllSmartPlaylistFilePaths();
|
||||
|
||||
public string GetSmartCollectionFilePath(string id);
|
||||
public string FindSmartCollectionFilePath(string id);
|
||||
public string[] FindAllSmartCollectionFilePaths();
|
||||
}
|
||||
|
||||
public class SmartPlaylistFileSystem : ISmartPlaylistFileSystem {
|
||||
public SmartPlaylistFileSystem(IServerApplicationPaths serverApplicationPaths) {
|
||||
StoragePath = Path.Combine(serverApplicationPaths.DataPath, "smartplaylists");
|
||||
if (!Directory.Exists(StoragePath)) { Directory.CreateDirectory(StoragePath); }
|
||||
public class SmartFileSystem : ISmartPlaylistFileSystem {
|
||||
public SmartFileSystem(IServerApplicationPaths serverApplicationPaths) {
|
||||
PlaylistStoragePath = Path.Combine(serverApplicationPaths.DataPath, "smartplaylists");
|
||||
CollectionStoragePath = Path.Combine(serverApplicationPaths.DataPath, "smartcollections");
|
||||
if (!Directory.Exists(PlaylistStoragePath)) { Directory.CreateDirectory(PlaylistStoragePath); }
|
||||
if (!Directory.Exists(CollectionStoragePath)) { Directory.CreateDirectory(CollectionStoragePath); }
|
||||
}
|
||||
public string StoragePath { get; }
|
||||
public string GetSmartPlaylistFilePath(SmartPlaylistId smartPlaylistId) {
|
||||
return Path.Combine(StoragePath, $"{smartPlaylistId}.yaml");
|
||||
public string PlaylistStoragePath { get; }
|
||||
public string CollectionStoragePath { get; }
|
||||
public string GetSmartPlaylistFilePath(string id) {
|
||||
return Path.Combine(PlaylistStoragePath, $"{id}.yaml");
|
||||
}
|
||||
public string FindSmartPlaylistFilePath(SmartPlaylistId smartPlaylistId) {
|
||||
return Directory.GetFiles(StoragePath, $"{smartPlaylistId}.yaml", SearchOption.AllDirectories).Concat(
|
||||
Directory.GetFiles(StoragePath, $"{smartPlaylistId}.yml", SearchOption.AllDirectories)
|
||||
public string FindSmartPlaylistFilePath(string id) {
|
||||
return Directory.GetFiles(PlaylistStoragePath, $"{id}.yaml", SearchOption.AllDirectories).Concat(
|
||||
Directory.GetFiles(PlaylistStoragePath, $"{id}.yml", SearchOption.AllDirectories)
|
||||
).Concat(
|
||||
Directory.GetFiles(StoragePath, $"{smartPlaylistId}.json", SearchOption.AllDirectories)
|
||||
Directory.GetFiles(PlaylistStoragePath, $"{id}.json", SearchOption.AllDirectories)
|
||||
).First();
|
||||
}
|
||||
public string[] FindAllSmartPlaylistFilePaths() {
|
||||
return Directory.GetFiles(StoragePath, "*.yaml", SearchOption.AllDirectories).Concat(
|
||||
Directory.GetFiles(StoragePath, "*.yml", SearchOption.AllDirectories)
|
||||
return Directory.GetFiles(PlaylistStoragePath, "*.yaml", SearchOption.AllDirectories).Concat(
|
||||
Directory.GetFiles(PlaylistStoragePath, "*.yml", SearchOption.AllDirectories)
|
||||
).Concat(
|
||||
Directory.GetFiles(StoragePath, "*.json", SearchOption.AllDirectories)
|
||||
Directory.GetFiles(PlaylistStoragePath, "*.json", SearchOption.AllDirectories)
|
||||
).ToArray();
|
||||
}
|
||||
public string GetSmartCollectionFilePath(string id) {
|
||||
return Path.Combine(CollectionStoragePath, $"{id}.yaml");
|
||||
}
|
||||
public string FindSmartCollectionFilePath(string id) {
|
||||
return Directory.GetFiles(CollectionStoragePath, $"{id}.yaml", SearchOption.AllDirectories).Concat(
|
||||
Directory.GetFiles(CollectionStoragePath, $"{id}.yml", SearchOption.AllDirectories)
|
||||
).Concat(
|
||||
Directory.GetFiles(CollectionStoragePath, $"{id}.json", SearchOption.AllDirectories)
|
||||
).First();
|
||||
}
|
||||
public string[] FindAllSmartCollectionFilePaths() {
|
||||
return Directory.GetFiles(CollectionStoragePath, "*.yaml", SearchOption.AllDirectories).Concat(
|
||||
Directory.GetFiles(CollectionStoragePath, "*.yml", SearchOption.AllDirectories)
|
||||
).Concat(
|
||||
Directory.GetFiles(CollectionStoragePath, "*.json", SearchOption.AllDirectories)
|
||||
).ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,12 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
Task SaveSmartPlaylistAsync(SmartPlaylistDto smartPlaylist);
|
||||
void DeleteSmartPlaylistById(SmartPlaylistId smartPlaylistId);
|
||||
void DeleteSmartPlaylist(SmartPlaylistDto smartPlaylist);
|
||||
|
||||
Task<SmartCollectionDto> GetSmartCollectionAsync(SmartCollectionId smartCollectionId);
|
||||
Task<SmartCollectionDto[]> GetAllSmartCollectionsAsync();
|
||||
Task SaveSmartCollectionAsync(SmartCollectionDto smartCollection);
|
||||
void DeleteSmartCollectionById(SmartCollectionId smartCollectionId);
|
||||
void DeleteSmartCollection(SmartCollectionDto smartCollection);
|
||||
}
|
||||
|
||||
public class Store : IStore {
|
||||
|
@ -59,5 +65,51 @@ namespace Jellyfin.Plugin.SmartPlaylist {
|
|||
if (File.Exists(smartPlaylist.Filename)) { File.Delete(smartPlaylist.Filename); }
|
||||
DeleteSmartPlaylistById(smartPlaylist.Id);
|
||||
}
|
||||
|
||||
private async Task<SmartCollectionDto> LoadCollectionAsync(string filename) {
|
||||
var r = await File.ReadAllTextAsync(filename);
|
||||
if (r.Equals("")) {
|
||||
r = "{}";
|
||||
}
|
||||
var dto = new DeserializerBuilder().Build().Deserialize<SmartCollectionDto>(r);
|
||||
if (dto == null)
|
||||
{
|
||||
throw new ApplicationException("");
|
||||
}
|
||||
if (dto.Id != Path.GetFileNameWithoutExtension(filename)) {
|
||||
dto.Id = Path.GetFileNameWithoutExtension(filename);
|
||||
}
|
||||
if (dto.Name != Path.GetFileNameWithoutExtension(filename)) {
|
||||
dto.Name = Path.GetFileNameWithoutExtension(filename);
|
||||
}
|
||||
if (dto.Filename != filename) {
|
||||
dto.Filename = filename;
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
public async Task<SmartCollectionDto> GetSmartCollectionAsync(SmartCollectionId smartCollectionId) {
|
||||
string filename = _fileSystem.FindSmartCollectionFilePath(smartCollectionId);
|
||||
return await LoadCollectionAsync(filename).ConfigureAwait(false);
|
||||
}
|
||||
public async Task<SmartCollectionDto[]> GetAllSmartCollectionsAsync() {
|
||||
var t = _fileSystem.FindAllSmartCollectionFilePaths().Select(LoadCollectionAsync).ToArray();
|
||||
await Task.WhenAll(t).ConfigureAwait(false);
|
||||
return t.Where(x => x != null).Select(x => x.Result).ToArray();
|
||||
}
|
||||
public async Task SaveSmartCollectionAsync(SmartCollectionDto smartCollection) {
|
||||
string filename = _fileSystem.GetSmartCollectionFilePath(smartCollection.Id);
|
||||
var text = new SerializerBuilder().Build().Serialize(smartCollection);
|
||||
await File.WriteAllTextAsync(filename, text);
|
||||
}
|
||||
public void DeleteSmartCollectionById(SmartCollectionId smartCollectionId) {
|
||||
try {
|
||||
string filename = _fileSystem.FindSmartCollectionFilePath(smartCollectionId);
|
||||
if (File.Exists(filename)) { File.Delete(filename); }
|
||||
} catch (System.InvalidOperationException) {}
|
||||
}
|
||||
public void DeleteSmartCollection(SmartCollectionDto smartCollection) {
|
||||
if (File.Exists(smartCollection.Filename)) { File.Delete(smartCollection.Filename); }
|
||||
DeleteSmartCollectionById(smartCollection.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,4 +2,6 @@ global using System;
|
|||
|
||||
global using UserId = System.Guid;
|
||||
global using PlaylistId = System.Guid;
|
||||
global using CollectionId = System.Guid;
|
||||
global using SmartPlaylistId = string;
|
||||
global using SmartCollectionId = string;
|
||||
|
|
Loading…
Add table
Reference in a new issue