diff --git a/.DS_Store b/.DS_Store index 2814a98..1163665 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 924a673..5580a72 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ +.DS_Store /obj/ /bin/ *.dll *.pdb *.cache -/LiteDb/ -.DS_Store output/* diff --git a/.vscode/launch.json b/.vscode/launch.json index 7e6feaf..373aa17 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,11 +11,16 @@ "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. "program": "${workspaceFolder}/bin/Debug/net6.0/als-tools.dll", - //"args": ["--locate=HG2;bx_tunner", "--folder=/Users/zenluiz/Desktop/Testes ALS"], - "args": ["--locate=kickbox;replika"], - // "args": ["--list"], - // "args": ["--initdb", "--folder=/Users/zenluiz/Desktop/Testes ALS"], - // "args": ["--initdb", "--folder=/Users/zenluiz/Splice"], + + //"args": ["locate", "--plugin-names", "HG2", "bx_tunner"], + //"args": ["locate", "--plugin-names", "kickbox", "replika"], + //"args": ["locate", "--plugin-names", "A1StereoControl"], + //"args": ["list"], + //"args": ["count"], + //"args": ["initdb", "--folders", "/Users\/zenluiz/Desktop/Testes ALS/Projects folder 1", "/Users/zenluiz/Desktop/Testes ALS/Projects folder 2"], + "args": ["initdb", "--folders", "~/Desktop/Testes ALS/Projects folder 1"], + //"args": ["initdb", "--folders", "/Users/zenluiz/Splice"], + "cwd": "${workspaceFolder}", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console "console": "internalConsole", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 34683dd..fc27c23 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -11,7 +11,11 @@ "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], - "problemMatcher": "$msCompile" + "problemMatcher": "$msCompile", + "group": { + "kind": "build", + "isDefault": true + } }, { "label": "clean", diff --git a/App.cs b/App.cs index f3df14b..d2bf427 100644 --- a/App.cs +++ b/App.cs @@ -2,8 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using AlsTools.CliOptions; using AlsTools.Core.Entities; using AlsTools.Core.Interfaces; +using AlsTools.Exceptions; +using CommandLine; using Microsoft.Extensions.Logging; namespace AlsTools @@ -11,63 +14,57 @@ namespace AlsTools public class App { private readonly ILogger logger; - private readonly ILiveProjectService liveProjectService; - - public App(ILogger logger, ILiveProjectService liveProjectService) + private readonly ILiveProjectAsyncService liveProjectService; + + public App(ILogger logger, ILiveProjectAsyncService liveProjectService) { this.logger = logger; this.liveProjectService = liveProjectService; } - public async Task Run(ProgramArgs args) + public async Task Run(ParserResult parserResult) { logger.LogDebug("App start"); - if (args.InitDb) - { - int count = 0; - if (!string.IsNullOrEmpty(args.File)) - count = liveProjectService.InitializeDbFromFile(args.File); - else - count = liveProjectService.InitializeDbFromFolder(args.Folder, args.IncludeBackups); - - await Console.Out.WriteLineAsync($"\nTotal of projects loaded into DB: {count}"); - } - else if (args.CountProjects) - { - int count = liveProjectService.CountProjects(); + await parserResult.WithParsedAsync(options => RunInitDb(options)); + await parserResult.WithParsedAsync(options => RunCount(options)); + await parserResult.WithParsedAsync(options => RunList(options)); + await parserResult.WithParsedAsync(options => RunLocate(options)); + await parserResult.WithNotParsedAsync(errors => { throw new CommandLineParseException(errors); }); + } - await Console.Out.WriteLineAsync($"\nTotal of projects in the DB: {count}"); - } - else if (args.ListPlugins) - { - var projects = liveProjectService.GetAllProjects().ToList(); - await PrintProjectsAndPlugins(projects); - await Console.Out.WriteLineAsync($"\nTotal of projects: {projects.Count}"); - } - else if (args.LocatePlugins) - { - var projects = liveProjectService.GetProjectsContainingPlugins(args.PluginsToLocate).ToList(); - await PrintProjectsAndPlugins(projects); - await Console.Out.WriteLineAsync($"\nTotal of projects: {projects.Count}"); - } - else if (args.Export) - { - var projects = liveProjectService.GetAllProjects().ToList(); - await ExportProjectsAndPlugins(projects); - await Console.Out.WriteLineAsync($"\nTotal of projects: {projects.Count}"); - } + private async Task RunInitDb(InitDbOptions options) + { + int count = 0; + if (options.Files.Any()) + count = await liveProjectService.InitializeDbFromFilesAsync(options.Files); else - { - throw new InvalidOperationException("Nothing to do?"); - } + count = await liveProjectService.InitializeDbFromFoldersAsync(options.Folders, options.IncludeBackups); + + await Console.Out.WriteLineAsync($"\nTotal of projects loaded into DB: {count}"); + } + + private async Task RunCount(CountOptions options) + { + int count = await liveProjectService.CountProjectsAsync(); + + await Console.Out.WriteLineAsync($"\nTotal of projects in the DB: {count}"); } - private Task ExportProjectsAndPlugins(List projects) + private async Task RunList(ListOptions options) { - throw new NotImplementedException(); + var projects = (await liveProjectService.GetAllProjectsAsync()).ToList(); + await PrintProjectsAndPlugins(projects); + await Console.Out.WriteLineAsync($"\nTotal of projects: {projects.Count}"); } + private async Task RunLocate(LocateOptions options) + { + var projects = (await liveProjectService.GetProjectsContainingPluginsAsync(options.PluginsToLocate)).ToList(); + await PrintProjectsAndPlugins(projects); + await Console.Out.WriteLineAsync($"\nTotal of projects: {projects.Count}"); + } + private async Task PrintProjectsAndPlugins(IEnumerable projects) { foreach (var p in projects) @@ -81,7 +78,7 @@ private async Task PrintProjectAndPlugins(LiveProject project) await Console.Out.WriteLineAsync($"Live version (creator): {project.LiveVersion}"); await Console.Out.WriteLineAsync($"Full path: {project.Path}"); await Console.Out.WriteLineAsync("\tTracks and plugins:"); - + if (project.Tracks.Count == 0) await Console.Out.WriteLineAsync("\t\tNo tracks found!"); diff --git a/CliOptions/CountOptions.cs b/CliOptions/CountOptions.cs new file mode 100644 index 0000000..72eda9b --- /dev/null +++ b/CliOptions/CountOptions.cs @@ -0,0 +1,9 @@ +using CommandLine; + +namespace AlsTools.CliOptions +{ + [Verb("count", HelpText = "Returns the total of projects stored in the als-tools database.")] + class CountOptions + { + } +} diff --git a/CliOptions/InitDbOptions.cs b/CliOptions/InitDbOptions.cs new file mode 100644 index 0000000..c4a597c --- /dev/null +++ b/CliOptions/InitDbOptions.cs @@ -0,0 +1,21 @@ + +using System.Collections.Generic; +using CommandLine; + +namespace AlsTools.CliOptions +{ + [Verb("initdb", + HelpText = @"Initialize the als-tools database with information extracted from Live sets, either from files or folders.")] + public class InitDbOptions + { + [Option("folders", Required = true, SetName = "folders", Min = 1, HelpText = "The root folders to look for Live Sets, recursively including children folders. This option is mutually exclusive with the --files option.")] + public IEnumerable Folders { get; set; } + + [Option("include-backups", SetName = "folders", Default = false, HelpText = "Set it to true to include backup Live Sets.")] + public bool IncludeBackups { get; set; } + + + [Option("files", Required = true, SetName = "files", Min = 1, HelpText = "The files to extract Live Set information from. This option is mutually exclusive with the --folders option.")] + public IEnumerable Files { get; set; } + } +} \ No newline at end of file diff --git a/CliOptions/ListOptions.cs b/CliOptions/ListOptions.cs new file mode 100644 index 0000000..e3680a4 --- /dev/null +++ b/CliOptions/ListOptions.cs @@ -0,0 +1,10 @@ +using CommandLine; + +namespace AlsTools.CliOptions +{ + [Verb("list", HelpText = "List all projects stored in the als-tools database.")] + public class ListOptions + { + + } +} \ No newline at end of file diff --git a/CliOptions/LocateOptions.cs b/CliOptions/LocateOptions.cs new file mode 100644 index 0000000..0a64821 --- /dev/null +++ b/CliOptions/LocateOptions.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using CommandLine; + +namespace AlsTools.CliOptions +{ + [Verb("locate", HelpText = "Locates projects containing given plugins by their names.")] + class LocateOptions + { + [Option("plugin-names", Required = true, Min = 1, HelpText = "The plugin names to locate projects by.")] + public IEnumerable PluginsToLocate { get; set; } + } +} \ No newline at end of file diff --git a/Config/DbOptions.cs b/Config/DbOptions.cs new file mode 100644 index 0000000..664b7d8 --- /dev/null +++ b/Config/DbOptions.cs @@ -0,0 +1,11 @@ +namespace AlsTools.Config +{ + public class DbOptions + { + public string DataLocation { get; set; } + + public string ServerUrl { get; set; } + + public string DocumentStoreName { get; set; } + } +} diff --git a/Config/LiteDbOptions.cs b/Config/LiteDbOptions.cs deleted file mode 100644 index 94982f8..0000000 --- a/Config/LiteDbOptions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace AlsTools.Config -{ - public class LiteDbOptions - { - public string DatabaseLocation { get; set; } - } -} diff --git a/Core/Entities/LiveProject.cs b/Core/Entities/LiveProject.cs index 6e7a663..01a4e9c 100644 --- a/Core/Entities/LiveProject.cs +++ b/Core/Entities/LiveProject.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using AlsTools.Core.Entities.Tracks; @@ -10,7 +11,7 @@ public LiveProject() Tracks = new List(); } - public int Id { get; set; } + public string Id { get; set; } public string Name { get; set; } diff --git a/Core/Interfaces/IEmbeddedDatabaseContext.cs b/Core/Interfaces/IEmbeddedDatabaseContext.cs new file mode 100644 index 0000000..ac65079 --- /dev/null +++ b/Core/Interfaces/IEmbeddedDatabaseContext.cs @@ -0,0 +1,12 @@ + +using Raven.Client.Documents; + +namespace AlsTools.Core.Interfaces +{ + public interface IEmbeddedDatabaseContext + { + IDocumentStore DocumentStore { get; } + + void Initialize(); + } +} diff --git a/Core/Interfaces/ILiveProjectAsyncRepository.cs b/Core/Interfaces/ILiveProjectAsyncRepository.cs new file mode 100644 index 0000000..b7e9202 --- /dev/null +++ b/Core/Interfaces/ILiveProjectAsyncRepository.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using AlsTools.Core.Entities; + +namespace AlsTools.Core.Interfaces +{ + public interface ILiveProjectAsyncRepository + { + Task InsertAsync(LiveProject project); + + Task InsertAsync(IEnumerable projects); + + Task> GetProjectsContainingPluginsAsync(IEnumerable pluginsToLocate); + + Task> GetAllProjectsAsync(); + + Task DeleteAllAsync(); + + Task CountProjectsAsync(); + } +} diff --git a/Core/Interfaces/ILiveProjectAsyncService.cs b/Core/Interfaces/ILiveProjectAsyncService.cs new file mode 100644 index 0000000..007bd90 --- /dev/null +++ b/Core/Interfaces/ILiveProjectAsyncService.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using AlsTools.Core.Entities; + +namespace AlsTools.Core.Interfaces +{ + public interface ILiveProjectAsyncService + { + Task InitializeDbFromFilesAsync(IEnumerable filePaths); + + Task InitializeDbFromFoldersAsync(IEnumerable folderPaths, bool includeBackupFolder); + + Task> GetAllProjectsAsync(); + + Task> GetProjectsContainingPluginsAsync(IEnumerable pluginsToLocate); + + Task CountProjectsAsync(); + } +} diff --git a/Core/Interfaces/ILiveProjectFileSystem.cs b/Core/Interfaces/ILiveProjectFileSystem.cs index bbe8b62..9cce338 100644 --- a/Core/Interfaces/ILiveProjectFileSystem.cs +++ b/Core/Interfaces/ILiveProjectFileSystem.cs @@ -5,8 +5,8 @@ namespace AlsTools.Core.Interfaces { public interface ILiveProjectFileSystem { - IEnumerable LoadProjectFilesFromDirectory(string folderPath, bool includeBackupFolder); + IEnumerable LoadProjectFilesFromDirectories(IEnumerable folderPaths, bool includeBackupFolder); - FileInfo LoadProjectFileFromSetFile(string setFilePath); + IEnumerable LoadProjectFilesFromSetFiles(IEnumerable setFilePaths); } } diff --git a/Core/Interfaces/ILiveProjectRepository.cs b/Core/Interfaces/ILiveProjectRepository.cs deleted file mode 100644 index 45ceb4b..0000000 --- a/Core/Interfaces/ILiveProjectRepository.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using AlsTools.Core.Entities; - -namespace AlsTools.Core.Interfaces -{ - public interface ILiveProjectRepository - { - bool Insert(LiveProject project); - - int Insert(IEnumerable projects); - - IEnumerable GetProjectsContainingPlugins(string[] pluginsToLocate); - - IEnumerable GetAllProjects(); - - void DeleteAll(); - - int CountProjects(); - } -} diff --git a/Core/Interfaces/ILiveProjectService.cs b/Core/Interfaces/ILiveProjectService.cs deleted file mode 100644 index ec8ae93..0000000 --- a/Core/Interfaces/ILiveProjectService.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using AlsTools.Core.Entities; - -namespace AlsTools.Core.Interfaces -{ - public interface ILiveProjectService - { - int InitializeDbFromFile(string filePath); - - int InitializeDbFromFolder(string folderPath, bool includeBackupFolder); - - IEnumerable GetAllProjects(); - - IEnumerable GetProjectsContainingPlugins(string[] pluginsToLocate); - - int CountProjects(); - } -} diff --git a/Core/Services/LiveProjectAsyncService.cs b/Core/Services/LiveProjectAsyncService.cs new file mode 100644 index 0000000..c49f5d5 --- /dev/null +++ b/Core/Services/LiveProjectAsyncService.cs @@ -0,0 +1,85 @@ + +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using AlsTools.Core.Entities; +using AlsTools.Core.Interfaces; +using Microsoft.Extensions.Logging; + +namespace AlsTools.Core.Services +{ + public class LiveProjectAsyncService : ILiveProjectAsyncService + { + private readonly ILogger logger; + private readonly ILiveProjectAsyncRepository repository; + private readonly ILiveProjectFileSystem fs; + private readonly ILiveProjectExtractor extractor; + + public LiveProjectAsyncService(ILogger logger, ILiveProjectAsyncRepository repository, ILiveProjectFileSystem fs, ILiveProjectExtractor extractor) + { + this.logger = logger; + this.repository = repository; + this.fs = fs; + this.extractor = extractor; + } + + public async Task CountProjectsAsync() + { + return await repository.CountProjectsAsync(); + } + + public async Task> GetAllProjectsAsync() + { + return await repository.GetAllProjectsAsync(); + } + + public async Task> GetProjectsContainingPluginsAsync(IEnumerable pluginsToLocate) + { + return await repository.GetProjectsContainingPluginsAsync(pluginsToLocate); + } + + public async Task InitializeDbFromFilesAsync(IEnumerable filePaths) + { + await repository.DeleteAllAsync(); + var project = LoadProjectsFromSetFiles(filePaths); + await repository.InsertAsync(project); + + return 1; + } + + public async Task InitializeDbFromFoldersAsync(IEnumerable folderPaths, bool includeBackupFolder) + { + await repository.DeleteAllAsync(); + var projects = LoadProjectsFromDirectories(folderPaths, includeBackupFolder); + await repository.InsertAsync(projects); + return projects.Count; + } + + private IList LoadProjectsFromSetFiles(IEnumerable filePaths) + { + var files = fs.LoadProjectFilesFromSetFiles(filePaths); + + return ExtractProjectsFromFiles(files); + } + + private IList LoadProjectsFromDirectories(IEnumerable folderPaths, bool includeBackupFolder) + { + var files = fs.LoadProjectFilesFromDirectories(folderPaths, includeBackupFolder); + + return ExtractProjectsFromFiles(files); + } + + private IList ExtractProjectsFromFiles(IEnumerable files) + { + var projects = new List(); + + foreach (var f in files) + { + var project = extractor.ExtractProjectFromFile(f); + projects.Add(project); + } + + return projects; + } + } +} diff --git a/Core/Services/LiveProjectService.cs b/Core/Services/LiveProjectService.cs deleted file mode 100644 index 147133a..0000000 --- a/Core/Services/LiveProjectService.cs +++ /dev/null @@ -1,77 +0,0 @@ - -using System.Collections.Generic; -using AlsTools.Core.Entities; -using AlsTools.Core.Interfaces; -using Microsoft.Extensions.Logging; - -namespace AlsTools.Core.Services -{ - public class LiveProjectService : ILiveProjectService - { - private readonly ILogger logger; - private readonly ILiveProjectRepository repository; - private readonly ILiveProjectFileSystem fs; - private readonly ILiveProjectExtractor extractor; - - public LiveProjectService(ILogger logger, ILiveProjectRepository repository, ILiveProjectFileSystem fs, ILiveProjectExtractor extractor) - { - this.logger = logger; - this.repository = repository; - this.fs = fs; - this.extractor = extractor; - } - - public int CountProjects() - { - return repository.CountProjects(); - } - - public IEnumerable GetAllProjects() - { - return repository.GetAllProjects(); - } - - public IEnumerable GetProjectsContainingPlugins(string[] pluginsToLocate) - { - return repository.GetProjectsContainingPlugins(pluginsToLocate); - } - - public int InitializeDbFromFile(string filePath) - { - repository.DeleteAll(); - var project = LoadProjectFromSetFile(filePath); - return repository.Insert(project) ? 1 : 0; - } - - public int InitializeDbFromFolder(string folderPath, bool includeBackupFolder) - { - repository.DeleteAll(); - var projects = LoadProjectsFromDirectory(folderPath, includeBackupFolder); - return repository.Insert(projects); - } - - private LiveProject LoadProjectFromSetFile(string setFilePath) - { - var file = fs.LoadProjectFileFromSetFile(setFilePath); - var project = extractor.ExtractProjectFromFile(file); - - return project; - } - - private IList LoadProjectsFromDirectory(string folderPath, bool includeBackupFolder) - { - List projects = new List(); - var files = fs.LoadProjectFilesFromDirectory(folderPath, includeBackupFolder); - - foreach (var f in files) - { - var project = extractor.ExtractProjectFromFile(f); - projects.Add(project); - } - - return projects; - } - - - } -} diff --git a/DevReferences.md b/DevReferences.md index 50ec02e..b78dc2c 100644 --- a/DevReferences.md +++ b/DevReferences.md @@ -1,8 +1,26 @@ -https://www.thecodebuzz.com/dependency-injection-console-app-using-generic-hostbuilder/ -https://dfederm.com/building-a-console-app-with-.net-generic-host/ +# Developer references + +## .NET +https://www.thecodebuzz.com/dependency-injection-console-app-using-generic-hostbuilder +https://dfederm.com/building-a-console-app-with-.net-generic-host +https://keestalkstech.com/2018/04/dependency-injection-with-ioptions-in-console-apps-in-net-core-2 +https://blog.bitscry.com/2017/05/30/appsettings-json-in-net-core-console-app + +## Logging - Serilog https://github.com/serilog/serilog-extensions-hosting -https://keestalkstech.com/2018/04/dependency-injection-with-ioptions-in-console-apps-in-net-core-2/ -https://blog.bitscry.com/2017/05/30/appsettings-json-in-net-core-console-app/ -https://social.technet.microsoft.com/wiki/contents/articles/53416.using-litedb-in-an-asp-net-core-api.aspx -https://blog.georgekosmidis.net/2019/11/02/using-litedb-in-an-asp-net-core-api/ -https://www.litedb.org/ \ No newline at end of file + +## NoSQL DB - RavenDB +https://ravendb.net +https://ravendb.net/docs/article-page/5.3/csharp/indexes/what-are-indexes +https://ravendb.net/docs/article-page/5.3/csharp/indexes/creating-and-deploying#using-assembly-scanner +https://ravendb.net/docs/article-page/5.3/csharp/client-api/faq/what-is-a-collection +https://ravendb.net/docs/article-page/5.3/csharp/indexes/querying/basics +https://ravendb.net/docs/article-page/5.3/csharp/client-api/operations/delete-by-query +https://ravendb.net/docs/article-page/5.3/Csharp/client-api/how-to/handle-document-relationships +https://ravendb.net/docs/article-page/5.3/csharp/indexes/creating-and-deploying +https://ravendb.net/docs/article-page/5.3/csharp/indexes/querying/filtering#where--in +https://ravendb.net/docs/article-page/5.3/csharp/studio/overview +https://demo.ravendb.net + +## Command line parser - commandline +https://github.com/commandlineparser/commandline \ No newline at end of file diff --git a/Exceptions/CommandLineParseException.cs b/Exceptions/CommandLineParseException.cs new file mode 100644 index 0000000..49ebcf1 --- /dev/null +++ b/Exceptions/CommandLineParseException.cs @@ -0,0 +1,37 @@ +using CommandLine; +using System; +using System.Collections.Generic; + +namespace AlsTools.Exceptions +{ + [System.Serializable] + public class CommandLineParseException : Exception + { + IEnumerable Errors { get; set; } + + public CommandLineParseException() { } + + + public CommandLineParseException(IEnumerable errors) + { + this.Errors = errors; + } + + public CommandLineParseException(string message) : base(message) { } + + public CommandLineParseException(string message, IEnumerable errors) : base(message) + { + this.Errors = errors; + } + public CommandLineParseException(string message, System.Exception inner) : base(message, inner) { } + + public CommandLineParseException(string message, IEnumerable errors, System.Exception inner) : base(message, inner) + { + this.Errors = errors; + } + + protected CommandLineParseException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/Infrastructure/EmbeddedDatabaseContext.cs b/Infrastructure/EmbeddedDatabaseContext.cs new file mode 100644 index 0000000..d013c6c --- /dev/null +++ b/Infrastructure/EmbeddedDatabaseContext.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; +using AlsTools.Config; +using AlsTools.Core.Interfaces; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Raven.Client.Documents; +using Raven.Client.Documents.Indexes; +using Raven.Embedded; + +namespace AlsTools.Infrastructure +{ + public class EmbeddedDatabaseContext : IEmbeddedDatabaseContext + { + private readonly ILogger logger; + private readonly IOptions options; + private bool isInitialized = false; + private IDocumentStore documentStore = null; + + public IDocumentStore DocumentStore + { + get + { + if (!isInitialized) + throw new InvalidOperationException("It is not possible to get the DocumentStore because the Embedded DB Server has not been started yet."); + + return documentStore ?? EmbeddedServer.Instance.GetDocumentStore(options.Value.DocumentStoreName); + } + } + + public EmbeddedDatabaseContext(ILogger logger, IOptions options) + { + this.logger = logger; + this.options = options; + } + + public void Initialize() + { + EmbeddedServer.Instance.StartServer(new ServerOptions + { + ServerUrl = options.Value.ServerUrl, + DataDirectory = Path.Combine(AppContext.BaseDirectory, options.Value.DataLocation) + }); + + isInitialized = true; + + DeployAllIndexes(); + } + + private void DeployAllIndexes() + { + // If an index already exists, it is ignored + IndexCreation.CreateIndexes(typeof(EmbeddedDatabaseContext).Assembly, DocumentStore); + } + } +} diff --git a/Infrastructure/FileSystem/LiveProjectFileSystem.cs b/Infrastructure/FileSystem/LiveProjectFileSystem.cs index e9af87d..6a6a5d3 100644 --- a/Infrastructure/FileSystem/LiveProjectFileSystem.cs +++ b/Infrastructure/FileSystem/LiveProjectFileSystem.cs @@ -8,25 +8,60 @@ namespace AlsTools.Infrastructure.FileSystem { public class LiveProjectFileSystem : ILiveProjectFileSystem { - public IEnumerable LoadProjectFilesFromDirectory(string folderPath, bool includeBackupFolder) + private readonly UserFolderHandler userFolderHandler; + + public LiveProjectFileSystem(UserFolderHandler userFolderHandler) + { + this.userFolderHandler = userFolderHandler; + } + + public IEnumerable LoadProjectFilesFromDirectories(IEnumerable folderPaths, bool includeBackupFolder) + { + var result = new List(); + + foreach (var folderPath in folderPaths) + { + var files = GetProjectFilesFromSingleDirectory(folderPath, includeBackupFolder); + result.AddRange(files); + } + + return result; + } + + public IEnumerable LoadProjectFilesFromSetFiles(IEnumerable setFilePaths) { - var d = new DirectoryInfo(folderPath); - var files = d.GetFiles("*.als", new EnumerationOptions() { RecurseSubdirectories = true }).AsEnumerable(); + var result = new List(); + + foreach (var filePath in setFilePaths) + { + var file = GetProjectFileFromSetFile(filePath); + result.Add(file); + } + + return result; + } + + private IEnumerable GetProjectFilesFromSingleDirectory(string folderPath, bool includeBackupFolder) + { + var path = userFolderHandler.GetFullPath(folderPath); + var dirInfo = new DirectoryInfo(path); + var files = dirInfo.GetFiles("*.als", new EnumerationOptions() { RecurseSubdirectories = true }).AsEnumerable(); if (!includeBackupFolder) files = files.Where(x => !x.FullName.Contains(@"/Backup/", StringComparison.InvariantCultureIgnoreCase)); return files; } - public FileInfo LoadProjectFileFromSetFile(string setFilePath) + + private FileInfo GetProjectFileFromSetFile(string setFilePath) { - FileInfo f = new FileInfo(setFilePath); + var path = userFolderHandler.GetFullPath(setFilePath); + FileInfo file = new FileInfo(path); - if (!f.Exists) - throw new FileNotFoundException($"The specified file does not exist ({setFilePath})"); + if (!file.Exists) + throw new FileNotFoundException($"The specified file does not exist ({path})"); - return f; + return file; } - } } diff --git a/Infrastructure/FileSystem/UserFolderHandler.cs b/Infrastructure/FileSystem/UserFolderHandler.cs new file mode 100644 index 0000000..acfc782 --- /dev/null +++ b/Infrastructure/FileSystem/UserFolderHandler.cs @@ -0,0 +1,30 @@ +using System.IO; + +namespace AlsTools.Infrastructure.FileSystem +{ + public class UserFolderHandler + { + private readonly string userHomeFolder; + + public UserFolderHandler(string userHomeFolder) + { + this.userHomeFolder = userHomeFolder; + } + + /// + /// In *nix-like systems (linux and macOS, for instance), a path starting with "~/" indicates it is under the user home directory. + /// In these cases, this method returns the expanded, full path of the folder or file passed in the parameter. + /// + /// The original path to get the correct full path for + /// If the path does not start with "~/", then it returns the original . Otherwise, it returns the expanded, full path. + public string GetFullPath(string path) + { + if (!path.StartsWith("~/")) + return path; + + var pathWithoutTildeSlash = path.Substring(2); + + return Path.Combine(userHomeFolder, pathWithoutTildeSlash); + } + } +} \ No newline at end of file diff --git a/Infrastructure/ILiteDbContext.cs b/Infrastructure/ILiteDbContext.cs deleted file mode 100644 index ab2e453..0000000 --- a/Infrastructure/ILiteDbContext.cs +++ /dev/null @@ -1,9 +0,0 @@ -using LiteDB; - -namespace AlsTools.Infrastructure -{ - public interface ILiteDbContext - { - LiteDatabase Database { get; } - } -} diff --git a/Infrastructure/Indexes/LiveProjects_ByPluginNames.cs b/Infrastructure/Indexes/LiveProjects_ByPluginNames.cs new file mode 100644 index 0000000..19939af --- /dev/null +++ b/Infrastructure/Indexes/LiveProjects_ByPluginNames.cs @@ -0,0 +1,23 @@ + + +using System.Linq; +using AlsTools.Core.Entities; +using Raven.Client.Documents.Indexes; + +namespace AlsTools.Infrastructure.Indexes +{ + public class LiveProjects_ByPluginNames : AbstractIndexCreationTask + { + public LiveProjects_ByPluginNames() + { + Map = projects => + from project in projects + from track in project.Tracks + from plugin in track.Plugins + select new + { + plugin.Value.Name + }; + } + } +} diff --git a/Infrastructure/LiteDbContext.cs b/Infrastructure/LiteDbContext.cs deleted file mode 100644 index 97e12da..0000000 --- a/Infrastructure/LiteDbContext.cs +++ /dev/null @@ -1,16 +0,0 @@ -using AlsTools.Config; -using LiteDB; -using Microsoft.Extensions.Options; - -namespace AlsTools.Infrastructure -{ - public class LiteDbContext : ILiteDbContext - { - public LiteDatabase Database { get; } - - public LiteDbContext(IOptions options) - { - Database = new LiteDatabase(options.Value.DatabaseLocation); - } - } -} diff --git a/Infrastructure/Repositories/LiveProjectRavenDBRepository.cs b/Infrastructure/Repositories/LiveProjectRavenDBRepository.cs new file mode 100644 index 0000000..269e3ea --- /dev/null +++ b/Infrastructure/Repositories/LiveProjectRavenDBRepository.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AlsTools.Core.Entities; +using AlsTools.Core.Interfaces; +using AlsTools.Infrastructure.Indexes; +using Microsoft.Extensions.Logging; +using Raven.Client.Documents; +using Raven.Client.Documents.BulkInsert; +using Raven.Client.Documents.Linq; +using Raven.Client.Documents.Operations; +using Raven.Client.Documents.Queries; + +namespace AlsTools.Infrastructure.Repositories +{ + public class LiveProjectRavenRepository : ILiveProjectAsyncRepository + { + private readonly ILogger logger; + private readonly IEmbeddedDatabaseContext dbContext; + private readonly IDocumentStore store; + private readonly string collectionName; + + public LiveProjectRavenRepository(ILogger logger, IEmbeddedDatabaseContext dbContext) + { + this.logger = logger; + this.dbContext = dbContext; + this.store = dbContext.DocumentStore; + this.collectionName = store.Conventions.GetCollectionName(typeof(LiveProject)); + } + + public async Task InsertAsync(LiveProject project) + { + using (var session = store.OpenAsyncSession()) + { + await session.StoreAsync(project); + await session.SaveChangesAsync(); + } + + logger.LogDebug("Inserted project {ProjectName}", project.Name); + } + + public async Task InsertAsync(IEnumerable projects) + { + BulkInsertOperation bulkInsert = null; + + try + { + bulkInsert = store.BulkInsert(); + int count = 0; + foreach (var project in projects) + { + await bulkInsert.StoreAsync(project); + count++; + } + + logger.LogDebug("Inserted {InsertedProjects} projects", count); + } + finally + { + if (bulkInsert != null) + await bulkInsert.DisposeAsync().ConfigureAwait(false); + } + } + + public async Task> GetProjectsContainingPluginsAsync(IEnumerable pluginsToLocate) + { + using (var session = store.OpenAsyncSession()) + { + var results = await session + .Query() + .Where(plugin => plugin.Name.In(pluginsToLocate)) + .ToListAsync(); + + return results; + } + } + + public async Task> GetAllProjectsAsync() + { + using (var session = store.OpenAsyncSession()) + { + return await session.Query().ToListAsync(); + } + } + + public async Task DeleteAllAsync() + { + var operation = await store + .Operations + .SendAsync(new DeleteByQueryOperation($"from {collectionName}")); + + operation.WaitForCompletion(TimeSpan.FromSeconds(5)); + } + + public async Task CountProjectsAsync() + { + using (var session = store.OpenAsyncSession()) + { + return await session.Query().CountAsync(); + } + } + } +} diff --git a/Infrastructure/Repositories/LiveProjectRepository.cs b/Infrastructure/Repositories/LiveProjectRepository.cs deleted file mode 100644 index 37dba97..0000000 --- a/Infrastructure/Repositories/LiveProjectRepository.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using AlsTools.Core.Entities; -using AlsTools.Core.Interfaces; -using LiteDB; -using Microsoft.Extensions.Logging; - -namespace AlsTools.Infrastructure.Repositories -{ - public class LiveProjectRepository : ILiveProjectRepository - { - private readonly LiteDatabase liteDb; - private readonly ILogger logger; - private readonly ILiteDbContext dbContext; - - public LiveProjectRepository(ILogger logger, ILiteDbContext dbContext) - { - this.liteDb = dbContext.Database; - this.logger = logger; - this.dbContext = dbContext; - } - - public int CountProjects() - { - return liteDb.GetCollection("LiveProject").Count(); - } - - public void DeleteAll() - { - var deletedCount = liteDb.GetCollection("LiveProject").DeleteAll(); - logger.LogDebug("Deleted {DeletedCount} projects", deletedCount); - } - - public IEnumerable GetAllProjects() - { - return liteDb.GetCollection("LiveProject").FindAll(); - } - - public IEnumerable GetProjectsContainingPlugins(string[] pluginsToLocate) - { - //TODO: implement it correctly, using DB query - var projects = GetAllProjects(); - IList res = new List(); - foreach (var proj in projects) - { - if (proj.Tracks.Any(track => track.Plugins.Any(plugin => pluginsToLocate.Any(plugToLocate => plugin.Key.Contains(plugToLocate, StringComparison.InvariantCultureIgnoreCase))))) - res.Add(proj); - } - - return res.AsEnumerable(); - } - - public bool Insert(LiveProject project) - { - var col = liteDb.GetCollection("LiveProject"); - var res = col.Insert(project); - - // Create an index over the Name property (if it doesn't exist) - col.EnsureIndex(x => x.Name); - - logger.LogDebug("Insert result {Result}", res); - - return res; - } - - public int Insert(IEnumerable projects) - { - var col = liteDb.GetCollection("LiveProject"); - var res = col.InsertBulk(projects); - - // Create an index over the Name property (if it doesn't exist) - col.EnsureIndex(x => x.Name); - - logger.LogDebug("Inserted {InsertedProjects} projects", res); - - return res; - } - } -} diff --git a/Program.cs b/Program.cs index 7322cba..5e5f74b 100644 --- a/Program.cs +++ b/Program.cs @@ -1,13 +1,14 @@ using System; using System.IO; -using System.Linq; using System.Threading.Tasks; +using AlsTools.CliOptions; using AlsTools.Config; using AlsTools.Core.Interfaces; using AlsTools.Core.Services; using AlsTools.Infrastructure; using AlsTools.Infrastructure.FileSystem; using AlsTools.Infrastructure.Repositories; +using CommandLine; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -22,6 +23,11 @@ class Program private static async Task Main(string[] args) { + Log.Debug("Parsing arguments"); + var parserResult = Parser.Default.ParseArguments(args); + if (parserResult.Tag == ParserResultType.NotParsed) + return ProgramReturnCodes.CommandParseError; + Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Information) @@ -38,20 +44,21 @@ private static async Task Main(string[] args) try { - Log.Debug("Parsing arguments"); - var arguments = ParseArguments(args); + Log.Debug("Starting database server"); + var embeddedDbContext = services.GetRequiredService(); + embeddedDbContext.Initialize(); Log.Debug("Starting application"); var app = services.GetRequiredService(); - await app.Run(arguments); + await app.Run(parserResult); - Log.Debug("Returning 0"); - return 0; + Log.Debug("Returning {ReturnCode}", ProgramReturnCodes.Ok); + return ProgramReturnCodes.Ok; } catch (Exception ex) { - Log.Fatal(ex, "An error occured. Returning code 1"); - return 1; + Log.Fatal(ex, "An error occurred. Returning code {ErrorCode}", ProgramReturnCodes.UnhandledError); + return ProgramReturnCodes.UnhandledError; } finally { @@ -82,114 +89,24 @@ private static void ConfigureServices(IServiceCollection serviceCollection) serviceCollection.AddSingleton(configuration); // Add DbContext - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + + // Add some helpers + serviceCollection.AddSingleton(svcProvider => + new UserFolderHandler(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile, Environment.SpecialFolderOption.None))); // Add services serviceCollection - .AddTransient() - .AddTransient() + .AddTransient() + .AddTransient() .AddTransient() .AddTransient(); - serviceCollection.Configure(configuration.GetSection("LiteDbOptions")); + serviceCollection.Configure(configuration.GetSection(nameof(DbOptions))); // Add app serviceCollection.AddTransient(); } - private static ProgramArgs ParseArguments(string[] args) - { - var arguments = GetArguments(args); - ValidateArguments(arguments); - - PrintArguments(arguments); - - return arguments; - } - - private static void PrintArguments(ProgramArgs args) - { - Log.Debug("Parameters: {@Args}", args); - } - - private static ProgramArgs GetArguments(string[] arguments) - { - var result = new ProgramArgs(); - var args = arguments.ToList(); - - int indexLocate = args.FindIndex(x => x.StartsWith("--locate=")); - if (indexLocate >= 0) - { - var parts = args[indexLocate].Split('='); - if (parts.Count() != 2) - throw new ArgumentException("Please specify a semicolon separated list of plugin names to locate!"); - - result.LocatePlugins = true; - result.PluginsToLocate = parts[1].Split(';'); - } - - if (args.IndexOf("--initdb") >= 0) - result.InitDb = true; - - if (args.IndexOf("--count") >= 0) - result.CountProjects = true; - - if (args.IndexOf("--list") >= 0) - result.ListPlugins = true; - - if (args.IndexOf("--includebackups") >= 0) - result.IncludeBackups = true; - - int indexFolder = args.FindIndex(x => x.StartsWith("--folder=")); - if (indexFolder >= 0) - { - var parts = args[indexFolder].Split('='); - if (parts.Count() != 2) - throw new ArgumentException("Please specify a folder path!"); - - result.Folder = parts[1]; - } - - int indexFile = args.FindIndex(x => x.StartsWith("--file=")); - if (indexFile >= 0) - { - var parts = args[indexFile].Split('='); - if (parts.Count() != 2) - throw new ArgumentException("Please specify a file path!"); - - result.File = parts[1]; - } - - int indexExport = args.FindIndex(x => x.StartsWith("--export=")); - if (indexExport >= 0) - { - var parts = args[indexFolder].Split('='); - if (parts.Count() != 2) - throw new ArgumentException("Please specify a file path!"); - - result.ExportFile = parts[1]; - } - - return result; - } - - private static void ValidateArguments(ProgramArgs args) - { - if (args.InitDb) - { - // Folder or file is always mandatory for initializing the DB! - if ((string.IsNullOrWhiteSpace(args.File) && string.IsNullOrWhiteSpace(args.Folder)) || - (!string.IsNullOrWhiteSpace(args.File) && !string.IsNullOrWhiteSpace(args.Folder))) - { - throw new ArgumentException("Please specify either a folder or file at least"); - } - } - - if ((args.ListPlugins && args.LocatePlugins && args.InitDb && args.CountProjects && args.Export) || - (!args.ListPlugins && !args.LocatePlugins && !args.InitDb && !args.CountProjects && !args.Export)) - throw new ArgumentException("Please specify either --initdb or --count or --list or --locate or --export option"); - - //TODO: implement validation of all other possibilities - } } } diff --git a/ProgramArgs.cs b/ProgramArgs.cs deleted file mode 100644 index 0a280f3..0000000 --- a/ProgramArgs.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace AlsTools -{ - public class ProgramArgs - { - public ProgramArgs() - { - PluginsToLocate = new string[0]; - } - - public string Folder { get; set; } - - public string File { get; set; } - - public bool LocatePlugins { get; set; } - - public bool ListPlugins { get; set; } - - public string[] PluginsToLocate { get; set; } - - public bool IncludeBackups { get; set; } - - public bool InitDb { get; set; } - - public bool CountProjects { get; set; } - - public bool Export { get; set; } - - public string ExportFile { get; set; } - } -} - diff --git a/ProgramReturnCodes.cs b/ProgramReturnCodes.cs new file mode 100644 index 0000000..1822901 --- /dev/null +++ b/ProgramReturnCodes.cs @@ -0,0 +1,11 @@ +namespace AlsTools +{ + public static class ProgramReturnCodes + { + public static int Ok = 0; + + public static int CommandParseError = -1; + + public static int UnhandledError = -2; + } +} \ No newline at end of file diff --git a/README.md b/README.md index a5d10dc..fdfc73f 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,130 @@ # Ableton Live Set tools ## Introduction -Use this tool to list all Ableton Live sets and their plugins or locate projects which are using some plugin. + +Ableton Live Set tools, or simply als-tools, brings easy-to-use search, listing, counting and many other capabilities over your Ableton Live Set files (*.als). + +> Notice: from now on, the term **project** will be used in place of **Ableton Live Set**, just for simplicity. + +## Current features + +- Scan multiple folders for *.als files, extract data from these files and save them in a database. +- List all projects stored in the database. +- Count the number of projects stored in the database. +- Locate projects containing one or more plugins, by plugin name. + +## Future enhancements + +Some of the most exciting future enhancements are: + +- 💥 **[Web front-end](https://github.com/luizen/als-tools/issues/14)**: a beautiful and easy-to-use web front-end; +- 💥 **[Interactive command line](https://github.com/luizen/als-tools/issues/7)**: navigate the options using a textual menu directly in your terminal! Take a look at [this project](https://github.com/shibayan/Sharprompt) for examples. +- 💥 **[Statistics](https://github.com/luizen/als-tools/issues/11)**: statistics like the number of tracks per project, most used devices/plugins, projects with most number of tracks, etc. Not only text/tables, but also nice charts. +- 💥 **[Powerful search/filtering](https://github.com/luizen/als-tools/issues/10)**: it will be possible to locate and filter projects by several properties, like plugin names, plugin types, device names, track names, track types, track count, etc. + +For the complete (and ever growing) list of planned, future enhancements, please visit the [Issues](https://github.com/luizen/als-tools/issues) page. ## Building -``` + +> This is a console application, which means all commands are required to be run in a command-line interpreter / terminal emulator. Some examples: +> +> - Windows: [Command Prompt (cmd.exe)](https://en.wikipedia.org/wiki/Cmd.exe), [PowerShell](https://en.wikipedia.org/wiki/PowerShell) or [Windows Terminal](https://en.wikipedia.org/wiki/Windows_Terminal); +> - macOS: [Terminal](https://en.wikipedia.org/wiki/Terminal_(macOS)) or other alternatives, like the great [iTerm2](https://iterm2.com); +> - Linux: [GNOME Terminal](https://en.wikipedia.org/wiki/GNOME_Terminal), [Konsole](https://en.wikipedia.org/wiki/Konsole); +> +> Click [here](https://en.wikipedia.org/wiki/List_of_terminal_emulators) for a list of terminal emulators/consoles. + +```programming dotnet build *.sln --configuration Release ``` ## Running -Supposing your Live sets are under `/Users/myuser/Music/Projects`, the following command **must be executed first** so that it reads all Live sets plus its plugins and loads them into the application database for further analysis. -``` -dotnet run --no-build --initdb --folder=/Users/myuser/Music/Projects -``` +> Right now there aren't any platform-specific full package, binary releases (Windows, macOS, Linux). So the way to run the tool is to download its source-code, build it and run it yourself. Check the [Development dependencies section](#development-dependencies) for more details. A [github issue (#21)](https://github.com/luizen/als-tools/issues/21) has already been created to handle this as a future enhancement. -After the database is initialized, you can execute further commands. +1. Initialize the database with data extracted from Live sets files (*.als). -- To count how many projects there are in the database: - ``` - dotnet run --no-build --count - ``` + Supposing your projects are under `/Users/myuser/Music/My Live Projects` and `/Users/myuser/Splice`, the following command ❗must be executed first❗ so that it **a)** scans all projects, extracting project information plus their details (currently: the tracks, plugins and devices) and **b)** loads them into the application database for further analysis. -- To list all Live projects and its plugins: + ```programming + dotnet run initdb --folders "/Users/myuser/Music/My Live Projects" "/Users/myuser/Splice" ``` - dotnet run --no-build --list + +2. After the database is initialized, further commands can be executed. + +- To count how many projects the database is loaded with: + + ```programming + dotnet run count ``` -- To locate all projects containing at least one of the plugins: +- To list all projects, its plugins, devices and tracks: + + ```programming + dotnet run list ``` - dotnet run --no-build --locate=plugin1;plugin2 ... + +- To locate all projects containing at least one of the plugins (_contains plugin name_): + + ```programming + dotnet run locate --plugin-names plugin1 "plugin 2" [...] ``` - > Where *plugin1* and *plugin2*, etc, should be the names of the plugins to locate projects using them. - > Example: dotnet run --no-build --locate="Abbey Road Vinyl";HG-2;bx_solo -## Next steps -- Export to Text, CSV, HTML, etc. -- Find a way to locate plugins using LiteDb own API. \ No newline at end of file + > Where **plugin1** and **"plugin 2"**, etc, should be the names of the plugins to locate projects using them. + > Example: + > + > ```programming + > dotnet run --plugin-names "Abbey Road Vinyl" HG-2 bx_solo + > ``` + +## Help and commands (verbs) + +To see all available command line verbs and options, just execute the following command: + +```programming +dotnet run +``` + +Example of output: +```programming +als-tools 1.0.0 +Copyright (C) 2022 als-tools + +ERROR(S): + No verb selected. + + initdb Initialize the als-tools database with information extracted from Live sets, either from files or folders. + + count Returns the total of projects stored in the als-tools database. + + list List all projects stored in the als-tools database. + + locate Locates projects containing given plugins by their names. + + help Display more information on a specific command. + + version Display version information. +``` + +## System requirements + +### Operating System + +Since not all music producers (Ableton Live users) work in/with the same platform / operating system, `als-tools` is being developed to be **cross-platform**, meaning it can be run on + +- **Windows** +- **macOS** +- **Linux** (even though Ableton Live does not run on Linux) + +### Development dependencies + +The `als-tools` project is currently developed using [.NET 6](https://docs.microsoft.com/en-us/dotnet/). To build and run the tool from its source-code, the **.NET 6 SDK** must be installed on your computer. This includes the SDK itself and Runtime packages as well. + +Click [here](https://dotnet.microsoft.com/en-us/download) to visit the .NET download page. + +## Tech stack + +- [.NET 6](https://docs.microsoft.com/en-us/dotnet/) console application +- [RavenDB](http://ravendb.net) - Embedded NoSQL document database +- [Serilog](http://serilog.net) - Logging library +- [CommandLineParser](https://github.com/commandlineparser/commandline) - CLI parameters parsing diff --git a/TEMP.txt b/TEMP.txt index e16df07..e69de29 100644 --- a/TEMP.txt +++ b/TEMP.txt @@ -1,100 +0,0 @@ - // var col = liteDb.GetCollection("LiveProject"); - - // var colall = liteDb.GetCollection("LiveProject"); - // var all = colall.FindAll().Where(pr => pr.Tracks.Any(tr => tr.Plugins.Any(pl => pl.Value.Name.ToLower() == "decapitator"))).ToList(); - - // // var pluginsList = pluginsToLocate - - // // var q1 = col.Find(proj => proj.Tracks != null && proj.Tracks.Any(track => track.Plugins != null && track - // // .Plugins.Any(plugin => pluginsToLocate.Contains(plugin.Key)) - // // )).ToList(); - - // var q1 = col.Query().Where(proj => proj.Name == "Industrial Acid Techno Youtube.als"); - // // var col1 = q1.Select(x => x); - // var col1 = q1.First(); - - // // var proj = col1.First(); - - // var a = q1.Where(x => x.Tracks.Where(x => x.Plugins != null && x.Plugins.Count > 0).Any()).Select(x => x).ToList(); - - - // // var b = col.Query().Where(x => x.Tracks.Where(x => x.Plugins != null && x.Plugins.Any(p => p.Value.Name == "Decapitator")).Any()).Select(x => x).ToList(); - // // {LiteDB.LiteException: Any/All requires simple parameter on left side. Eg: `x => x.Phones.Select(p => p.Number).Any(n => n > 5)` - - // // var b = col.Query().Where(x => x.Tracks.Where(x => x.Plugins != null && x.Plugins.Keys.Any(k => k.Equals("Decapitator"))).Any()).Select(x => x).ToList(); - // // var b = col.Query().Where(x => x.Tracks.Where(x => x.Plugins.Where(p => p.Value.Name == "Decapitator").Count() > 0).Any()).Select(x => x).ToList(); - // var c = col - // .Query() - // .Where(proj => proj.Name == "Industrial Acid Techno Youtube.als") - // .Where(x => x.Tracks.Where(x => x.Plugins.Values.Where(v => v.Name.Length > 5).Count() > 0).Count() > 0) - // .Select(x => x) - // .ToList(); - - // var q1 = col.Find(proj => proj.Tracks.Count > 40) - // .Select(x => x.Tracks) - // .ToList(); - - // var q2 = col.FindAll().ToList(); - - // var q3 = col.Query().Select(x => x).ToList(); - - - - // var p1 = col - // .Query() - // .Where(proj => proj.Tracks.Any(track => track.Name.Length > 10)) - // .Select(proj => proj) - // .ToList(); - - // var projects = col - // .Query() - // .Where(proj => proj - // .Tracks.Any(track => track - // .Plugins.Any(plugin => pluginsToLocate.Contains(plugin.Key)) - // ) - // ) - // .Select(proj => proj) - // .ToEnumerable(); - - //return null; - - // var projects1 = col - // .Query() - // .Where(proj => proj.Plugins != null && proj.Plugins.Any(k => pluginsToLocate.Any(x => k.Name.Contains(x, StringComparison.InvariantCultureIgnoreCase)))) - // .Select(p => p) - // .ToEnumerable(); - - // var projects2 = col - // .Query() - // .Where(proj => proj.Plugins.Where(plugin => pluginsToLocate.Contains(plugin.Name)).Any()) - // .Select(p => p) - // .ToEnumerable(); - - // var projects3 = col - // .Query() - // .Where(proj => - // proj.Plugins.Where(plugin => - // pluginsToLocate.Any(p => p.Contains(plugin.Name, StringComparison.InvariantCultureIgnoreCase)) - // ).Any() - // ) - // .Select(p => p) - // .ToEnumerable(); - - // var projects4 = col - // .Include(x => x.Plugins) - // .FindAll() - // .Where(p => p.Plugins.Intersect(pluginsToLocate)) - - // var pluginToLocate = pluginsToLocate[0]; - // var col = liteDb.GetCollection("LiveProject"); - - // var query = @"SELECT { $.*, $.Plugins[*] FROM LiveProject } WHERE $.Plugins[*].Title LIKE '%" + pluginToLocate + "%'"; - // var s = liteDb.Execute(query).ToList(); - - // var res = col.Query() - // .Where(proj => proj.Plugins.Any(p => p.Key.Contains(pluginToLocate, StringComparison.InvariantCultureIgnoreCase)).Any()) - // .Select(x => x); - - // return res.ToEnumerable(); - - // return null; \ No newline at end of file diff --git a/als-tools.csproj b/als-tools.csproj index 4cccc64..c34f76c 100644 --- a/als-tools.csproj +++ b/als-tools.csproj @@ -10,7 +10,7 @@ - + @@ -18,9 +18,10 @@ - + + \ No newline at end of file diff --git a/appsettings.json b/appsettings.json index ff31d38..0c5cdd9 100644 --- a/appsettings.json +++ b/appsettings.json @@ -1,5 +1,7 @@ { - "LiteDbOptions": { - "DatabaseLocation": "LiteDb/AlsToolsDb.db" + "DbOptions": { + "DataLocation": "RavenDbData", + "ServerUrl": "http://localhost:8099", + "DocumentStoreName": "AlsToolsEmbeddedDocumentStore" } } \ No newline at end of file diff --git a/sample-live-sets/With Plugins Project/Ableton Project Info/Project8_1.cfg b/sample-live-sets/With Plugins Project/Ableton Project Info/Project8_1.cfg new file mode 100644 index 0000000..1f7116a Binary files /dev/null and b/sample-live-sets/With Plugins Project/Ableton Project Info/Project8_1.cfg differ diff --git "a/sample-live-sets/With Plugins Project/Icon\r" "b/sample-live-sets/With Plugins Project/Icon\r" new file mode 100644 index 0000000..e69de29 diff --git a/sample-live-sets/With Plugins Project/With Plugins.als b/sample-live-sets/With Plugins Project/With Plugins.als new file mode 100644 index 0000000..e27d831 Binary files /dev/null and b/sample-live-sets/With Plugins Project/With Plugins.als differ