public async void Start() { Plugin.log?.Debug("BeatSync Start()"); IsRunning = true; SetupComponents(); if (playlistManager != null) { var recentPlaylist = Plugin.config.RecentPlaylistDays > 0 ? playlistManager.GetOrAddPlaylist(BuiltInPlaylist.BeatSyncRecent) : null; if (recentPlaylist != null && Plugin.config.RecentPlaylistDays > 0) { var minDate = DateTime.Now - new TimeSpan(Plugin.config.RecentPlaylistDays, 0, 0, 0); int removedCount = recentPlaylist.RemoveAll(s => s.DateAdded < minDate); if (removedCount > 0) { Plugin.log?.Info($"Removed {removedCount} old songs from the RecentPlaylist."); recentPlaylist.RaisePlaylistChanged(); try { playlistManager.StorePlaylist(recentPlaylist); } catch (Exception ex) { Plugin.log?.Warn($"Unable to write {recentPlaylist.Filename}: {ex.Message}"); Plugin.log?.Debug(ex); } } else { Plugin.log?.Info("Didn't remove any songs from RecentPlaylist."); } } } var syncInterval = new TimeSpan(Plugin.modConfig.TimeBetweenSyncs.Hours, Plugin.modConfig.TimeBetweenSyncs.Minutes, 0); var nowTime = DateTime.Now; if (Plugin.config.LastRun + syncInterval <= nowTime) { if (Plugin.config.LastRun != DateTime.MinValue) { Plugin.log?.Info($"BeatSync ran {TimeSpanToString(nowTime - Plugin.config.LastRun)} ago"); } if (songHasher != null) { await songHasher.InitializeAsync().ConfigureAwait(false); Plugin.log?.Info($"Hashed {songHasher.HashDictionary.Count} songs in {CustomLevelsDirectory}."); } else { Plugin.log?.Error($"SongHasher was null."); } // Start downloader IJobBuilder jobBuilder = CreateJobBuilder(Plugin.config); SongDownloader songDownloader = new SongDownloader(); JobManager JobManager = new JobManager(Plugin.config.MaxConcurrentDownloads); JobManager.Start(CancelAllToken); Stopwatch sw = new Stopwatch(); sw.Start(); if (jobBuilder.SongTargets.Count() == 0) { Plugin.log?.Error("jobBuilder has no SongTargets."); } JobStats[] sourceStats = await songDownloader.RunAsync(Plugin.config, jobBuilder, JobManager).ConfigureAwait(false); // TODO: CancellationToken JobStats beatSyncStats = sourceStats.Aggregate((a, b) => a + b); await JobManager.CompleteAsync(); int recentPlaylistDays = Plugin.config.RecentPlaylistDays; DateTime cutoff = DateTime.Now - new TimeSpan(recentPlaylistDays, 0, 0, 0); foreach (SongTarget target in jobBuilder.SongTargets) { if (target is ITargetWithPlaylists targetWithPlaylists) { PlaylistManager?targetPlaylistManager = targetWithPlaylists.PlaylistManager; if (recentPlaylistDays > 0) { BeatSaberPlaylistsLib.Types.IPlaylist?recent = targetPlaylistManager?.GetOrAddPlaylist(BuiltInPlaylist.BeatSyncRecent); if (recent != null && recent.Count > 0) { int songsRemoved = recent.RemoveAll(s => s.DateAdded < cutoff); if (songsRemoved > 0) { recent.RaisePlaylistChanged(); } } } try { targetPlaylistManager?.StoreAllPlaylists(); } catch (AggregateException ex) { Plugin.log?.Error($"Error storing playlists: {ex.Message}"); foreach (var e in ex.InnerExceptions) { Plugin.log?.Debug(e); } } catch (Exception ex) { Plugin.log?.Error($"Error storing playlists: {ex.Message}"); Plugin.log?.Debug(ex); } } if (target is ITargetWithHistory targetWithHistory) { try { targetWithHistory.HistoryManager?.WriteToFile(); } catch (Exception ex) { Plugin.log?.Info($"Unable to save history at '{targetWithHistory.HistoryManager?.HistoryPath}': {ex.Message}"); } } } sw.Stop(); Plugin.log?.Info($"Finished after {sw.Elapsed.TotalSeconds}s: {beatSyncStats}"); Plugin.config.LastRun = DateTime.Now; Plugin.ConfigManager.SaveConfig(); SongCore.Loader loader = SongCore.Loader.Instance; SongCore.Loader.SongsLoadedEvent -= Loader_SongsLoadedEvent; SongCore.Loader.SongsLoadedEvent += Loader_SongsLoadedEvent; if (!SongCore.Loader.AreSongsLoading) { SongCore.Loader.SongsLoadedEvent -= Loader_SongsLoadedEvent; if (SongCore.Loader.AreSongsLoaded) { loader.RefreshSongs(); } } } else { Plugin.log?.Info($"BeatSync ran {TimeSpanToString(nowTime - Plugin.config.LastRun)} ago, skipping because TimeBetweenSyncs is {Plugin.modConfig.TimeBetweenSyncs}"); } }
static async Task Main(string[] args) { try { ConsoleLogWriter?consoleLogger = SetupLogging(); string version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0.0"; Logger.log.Info($"Starting BeatSyncConsole v{version}"); await CheckVersion().ConfigureAwait(false); ConfigManager = new ConfigManager(ConfigDirectory); bool validConfig = await ConfigManager.InitializeConfigAsync().ConfigureAwait(false); if (consoleLogger != null) { consoleLogger.LogLevel = ConfigManager.Config?.ConsoleLogLevel ?? BeatSyncLib.Logging.LogLevel.Info; } Config?config = ConfigManager.Config; if (validConfig && config != null && config.BeatSyncConfig != null) { SongFeedReaders.WebUtils.Initialize(new WebUtilities.HttpClientWrapper.HttpClientWrapper()); SongFeedReaders.WebUtils.WebClient.SetUserAgent("BeatSyncConsole/" + version); JobManager manager = new JobManager(config.BeatSyncConfig.MaxConcurrentDownloads); manager.Start(CancellationToken.None); IJobBuilder jobBuilder = await CreateJobBuilderAsync(config).ConfigureAwait(false); SongDownloader songDownloader = new SongDownloader(); Stopwatch sw = new Stopwatch(); sw.Start(); JobStats[] sourceStats = await songDownloader.RunAsync(config.BeatSyncConfig, jobBuilder, manager).ConfigureAwait(false); JobStats beatSyncStats = sourceStats.Aggregate((a, b) => a + b); await manager.CompleteAsync().ConfigureAwait(false); int recentPlaylistDays = config.BeatSyncConfig.RecentPlaylistDays; DateTime cutoff = DateTime.Now - new TimeSpan(recentPlaylistDays, 0, 0, 0); foreach (SongTarget?target in jobBuilder.SongTargets) { if (target is ITargetWithPlaylists targetWithPlaylists) { PlaylistManager?targetPlaylistManager = targetWithPlaylists.PlaylistManager; if (recentPlaylistDays > 0) { IPlaylist?recent = targetPlaylistManager?.GetOrAddPlaylist(BuiltInPlaylist.BeatSyncRecent); if (recent != null && recent.Count > 0) { int songsRemoved = recent.RemoveAll(s => s.DateAdded < cutoff); if (songsRemoved > 0) { recent.RaisePlaylistChanged(); } } } try { targetPlaylistManager?.StoreAllPlaylists(); } catch (AggregateException ex) { Logger.log.Error($"Error storing playlists: {ex.Message}"); foreach (var e in ex.InnerExceptions) { Logger.log.Debug(e); } } catch (Exception ex) { Logger.log.Error($"Error storing playlists: {ex.Message}"); Logger.log.Debug(ex); } } if (target is ITargetWithHistory targetWithHistory) { try { targetWithHistory.HistoryManager?.WriteToFile(); } catch (Exception ex) { Logger.log.Info($"Unable to save history at '{targetWithHistory.HistoryManager?.HistoryPath}': {ex.Message}"); } } } sw.Stop(); Logger.log.Info($"Finished after {sw.Elapsed.TotalSeconds}s: {beatSyncStats}"); config.BeatSyncConfig.LastRun = DateTime.Now; } else { Logger.log.Info("BeatSyncConsole cannot run without a valid config, exiting."); } LogManager.Stop(); LogManager.Wait(); Console.WriteLine("Press Enter to continue..."); Console.Read(); } catch (Exception ex) { string message = $"Fatal Error in BeatSyncConsole: {ex.Message}\n{ex.StackTrace}"; if (LogManager.IsAlive && LogManager.HasWriters && Logger.log != null) { Logger.log.Error(message); } else { ConsoleColor previousColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(message); Console.ForegroundColor = previousColor; } LogManager.Stop(); LogManager.Wait(); Console.WriteLine("Press Enter to continue..."); Console.Read(); } finally { LogManager.Abort(); } }