From b3e6d2e844c6e97b10f8c4d444fded5dfda7a2bf Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Thu, 31 Jul 2025 14:23:33 -0500 Subject: [PATCH 1/5] Updated DBSyncWatcher Removed logging of changes detected in files. --- FreeTubeSyncer/Library/DBSyncWatcher.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/FreeTubeSyncer/Library/DBSyncWatcher.cs b/FreeTubeSyncer/Library/DBSyncWatcher.cs index 3a2ca78..2abd29f 100644 --- a/FreeTubeSyncer/Library/DBSyncWatcher.cs +++ b/FreeTubeSyncer/Library/DBSyncWatcher.cs @@ -43,8 +43,6 @@ public class DBSyncWatcher var dbName = Path.GetFileName(e.FullPath); if (!WatchFiles.Keys.Contains(dbName)) return; - - Console.WriteLine("New Change in {0}", dbName); var data = File.ReadAllText(e.FullPath); foreach (var line in data.Split('\n')) From c9e4cc694b798bb4a5b9bc9fd3bb9fc49bea9d06 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Thu, 31 Jul 2025 14:24:10 -0500 Subject: [PATCH 2/5] Added Ping and UpdateCheck models. Added Ping and UpdateCheck models for quick pings for service being alive, and when the database was last updated. --- FreeTubeSyncer/Models/DatabaseModels/Ping.cs | 6 ++++++ FreeTubeSyncer/Models/DatabaseModels/UpdateCheck.cs | 8 ++++++++ 2 files changed, 14 insertions(+) create mode 100644 FreeTubeSyncer/Models/DatabaseModels/Ping.cs create mode 100644 FreeTubeSyncer/Models/DatabaseModels/UpdateCheck.cs diff --git a/FreeTubeSyncer/Models/DatabaseModels/Ping.cs b/FreeTubeSyncer/Models/DatabaseModels/Ping.cs new file mode 100644 index 0000000..e2a60c1 --- /dev/null +++ b/FreeTubeSyncer/Models/DatabaseModels/Ping.cs @@ -0,0 +1,6 @@ +namespace FreeTubeSyncer.Models.DatabaseModels; + +public class Ping +{ + public string AppVersion { get; set; } +} \ No newline at end of file diff --git a/FreeTubeSyncer/Models/DatabaseModels/UpdateCheck.cs b/FreeTubeSyncer/Models/DatabaseModels/UpdateCheck.cs new file mode 100644 index 0000000..42cf3ed --- /dev/null +++ b/FreeTubeSyncer/Models/DatabaseModels/UpdateCheck.cs @@ -0,0 +1,8 @@ +using System; + +namespace FreeTubeSyncer.Models.DatabaseModels; + +public class UpdateCheck +{ + public DateTime LastUpdated { get; set; } +} \ No newline at end of file From 0e07f21ffefe1f0b5a694a1279e6c2fe88626616 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Thu, 31 Jul 2025 14:24:32 -0500 Subject: [PATCH 3/5] Updated CSProj Removed Views, as is not needed. --- FreeTubeSyncer/FreeTubeSyncer.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/FreeTubeSyncer/FreeTubeSyncer.csproj b/FreeTubeSyncer/FreeTubeSyncer.csproj index bf74326..a7ed908 100644 --- a/FreeTubeSyncer/FreeTubeSyncer.csproj +++ b/FreeTubeSyncer/FreeTubeSyncer.csproj @@ -26,7 +26,6 @@ - From a88da7f6d07b6867287073828dce73a9d0f986e9 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Thu, 31 Jul 2025 14:26:20 -0500 Subject: [PATCH 4/5] Updated Syncer Added GetLastUpdated() to ISyncer interface. Updated code to use new /ping endpoint. Added GetLastUpdated() REST API call to fetch when the database was last updated. Clarified logging for when an Update is from a file, or from the REST API Server. Added logging for when a nw File Entry is processed, or when a File Entry is Updated. --- FreeTubeSyncer/REST/Syncer.cs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/FreeTubeSyncer/REST/Syncer.cs b/FreeTubeSyncer/REST/Syncer.cs index ea7b1a2..71ace55 100644 --- a/FreeTubeSyncer/REST/Syncer.cs +++ b/FreeTubeSyncer/REST/Syncer.cs @@ -27,6 +27,7 @@ public interface ISyncer void UpdateBaseUrl(string baseUrl); void SetEnabled(bool enabled); Task PingApi(); + Task GetLastUpdated(); } public class Syncer : ISyncer where T : class, IDataModel, new() @@ -71,11 +72,18 @@ public class Syncer : ISyncer where T : class, IDataModel, new() Console.WriteLine($"Pinging API at {_client.BuildUri(new RestRequest("/ping"))}..."); try { - var res = await _client.ExecuteHeadAsync(new RestRequest("/ping")); - if (res.StatusCode == HttpStatusCode.NotFound) + var res = await _client.GetAsync(new RestRequest("/ping")); + if (res == null) { // TODO: Replace with Logger - Console.WriteLine($"Ping response 404 Not Found, Server Online!"); + Console.WriteLine($"Ping returned null, not the server we are looking for!"); + return false; + } + + if (res.AppVersion == "0.1.3") + { + // TODO: Replace with Logger + Console.WriteLine($"Server Online! {res.AppVersion}"); return true; } } @@ -91,6 +99,12 @@ public class Syncer : ISyncer where T : class, IDataModel, new() return false; } + public async Task GetLastUpdated() + { + var res = await _client.GetAsync("/ping/lastUpdated"); + return res?.LastUpdated ?? DateTime.MinValue; + } + public async Task ReadDatabase() { if (!_enabled) return; @@ -115,7 +129,7 @@ public class Syncer : ISyncer where T : class, IDataModel, new() _entries.RemoveAll(x => x.EqualId(item.Id())); _entries.Add(item); // TODO: Replace with Logger - Console.WriteLine($"Posting {item.Id()}"); + Console.WriteLine($"Posting to REST: {item.Id()}"); await _client.PostJsonAsync(_restEndpoint, item); } } @@ -134,13 +148,13 @@ public class Syncer : ISyncer where T : class, IDataModel, new() if (data.Equals(entry)) continue; // TODO: Replace with Logger - Console.WriteLine($"Updated Entry for {_dbName} - {entry.Id()}"); + Console.WriteLine($"Updated Entry from REST for {_dbName} - {entry.Id()}"); _entries.RemoveAll(x => x.EqualId(entry.Id())); } else { // TODO: Replace with Logger - Console.WriteLine($"New Entry for {_dbName} - {entry.Id()}"); + Console.WriteLine($"New Entry from REST for {_dbName} - {entry.Id()}"); } _entries.Add(entry); @@ -185,9 +199,15 @@ public class Syncer : ISyncer where T : class, IDataModel, new() { var data = _entries.First(x => x.EqualId(entry.Id())); if (data.Equals(entry)) return; - + // TODO: Replace with Logger + Console.WriteLine($"File Entry {entry.Id()} updated for {_dbName}"); _entries.RemoveAll(x => x.EqualId(entry.Id())); } + else + { + // TODO: Replace with Logger + Console.WriteLine($"New File Entry {entry.Id()} for {_dbName}"); + } _entries.Add(entry); await _client.PostJsonAsync(_restEndpoint, entry); From 823bb11b838ab31151948d5c7209137827d72ec2 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Thu, 31 Jul 2025 14:28:36 -0500 Subject: [PATCH 5/5] Updated App Added Last Update stamp, for when the last update was in the database, to see if we have newer events to process. Applied settings for enabling/disabling syncers on startup. Updated SyncMonitor() to use new Update check, before iterating through all the syncers and fetching them. Added logging messages for when we are updating settings to reflect what has been changed. --- FreeTubeSyncer/App.axaml.cs | 75 +++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/FreeTubeSyncer/App.axaml.cs b/FreeTubeSyncer/App.axaml.cs index cf3a496..207aee9 100644 --- a/FreeTubeSyncer/App.axaml.cs +++ b/FreeTubeSyncer/App.axaml.cs @@ -32,6 +32,7 @@ public partial class App : Application private string? _oldSettings; private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1); private TimeSpan _checkInterval; + private DateTime _lastUpdated; public event EventHandler? SettingsChanged; @@ -67,10 +68,15 @@ public partial class App : Application _watcher = new DBSyncWatcher(path); _historySyncer = new Syncer(_watcher, Path.Join(path, "history.db"), "history.db", _settings.RestBaseUrl, "/history"); + _historySyncer.SetEnabled(_settings.SyncHistory); _playlistSyncer = new Syncer(_watcher, Path.Join(path, "playlists.db"), "playlists.db", _settings.RestBaseUrl, "/playlist"); + _playlistSyncer.SetEnabled(_settings.SyncPlaylist); _profileSyncer = new Syncer(_watcher, Path.Join(path, "profiles.db"), "profiles.db", _settings.RestBaseUrl, "/profile"); + _profileSyncer.SetEnabled(_settings.SyncProfile); _searchHistorySyncer = new Syncer(_watcher, Path.Join(path, "search-history.db"), "search-history.db", _settings.RestBaseUrl, "/searchHistory"); + _searchHistorySyncer.SetEnabled(_settings.SyncSearchHistory); _settingSyncer = new Syncer(_watcher, Path.Join(path, "settings.db"), "settings.db", _settings.RestBaseUrl, "/settings"); + _settingSyncer.SetEnabled(_settings.SyncSettings); _syncers = [ _historySyncer, @@ -155,6 +161,8 @@ public partial class App : Application await syncer.FetchDatabase(); } + _lastUpdated = await _syncers[0].GetLastUpdated(); + _semaphoreSlim.Release(); break; } @@ -173,8 +181,15 @@ public partial class App : Application var start = DateTime.Now; // TODO: Replace with Logger Console.WriteLine("Checking for updates..."); - foreach (var syncer in _syncers) - await syncer.FetchDatabase(); + var updateCheck = await _syncers[0].GetLastUpdated(); + if (_lastUpdated < updateCheck) + { + // TODO: Replace with Logger + Console.WriteLine($"Update Found, fetching updates..."); + _lastUpdated = updateCheck; + foreach (var syncer in _syncers) + await syncer.FetchDatabase(); + } lastCheck = DateTime.Now; var end = DateTime.Now - start; _semaphoreSlim.Release(); @@ -207,20 +222,64 @@ public partial class App : Application private async void HandleSettingsChanged(object? sender, EventArgs e) { + // TODO: Replace with Logger + Console.WriteLine("Settings have changed. Updating Settings..."); await _semaphoreSlim.WaitAsync(); var old = JsonSerializer.Deserialize(_oldSettings!); if (_settings!.RestBaseUrl != old!.RestBaseUrl) { + // TODO: Replace with Logger + Console.WriteLine($"Updating syncers with new URL: {_settings.RestBaseUrl}."); foreach (var syncer in _syncers!) syncer.UpdateBaseUrl(_settings.RestBaseUrl); } - if (old.CheckInterval != _settings.CheckInterval) _checkInterval = TimeSpan.FromSeconds(_settings.CheckInterval); - if (old.SyncHistory != _settings.SyncHistory) _historySyncer!.SetEnabled(_settings.SyncHistory); - if (old.SyncPlaylist != _settings.SyncPlaylist) _playlistSyncer!.SetEnabled(_settings.SyncPlaylist); - if (old.SyncProfile != _settings.SyncProfile) _profileSyncer!.SetEnabled(_settings.SyncProfile); - if (old.SyncSearchHistory != _settings.SyncSearchHistory) _searchHistorySyncer!.SetEnabled(_settings.SyncSearchHistory); - if (old.SyncSettings != _settings.SyncSettings) _settingSyncer!.SetEnabled(_settings.SyncSettings); + if (old.CheckInterval != _settings.CheckInterval) + { + // TODO: Replace with Logger + Console.WriteLine($"Updating Check Interval to {_settings.CheckInterval}."); + _checkInterval = TimeSpan.FromSeconds(_settings.CheckInterval); + } + + if (old.SyncHistory != _settings.SyncHistory) + { + // TODO: Replace with Logger + Console.WriteLine("History Syncer: " + (_settings.SyncHistory ? "Enabled" : "Disabled")); + _historySyncer!.SetEnabled(_settings.SyncHistory); + await _historySyncer.FetchDatabase(); + } + + if (old.SyncPlaylist != _settings.SyncPlaylist) + { + // TODO: Replace with Logger + Console.WriteLine("Playlist Syncer: " + (_settings.SyncHistory ? "Enabled" : "Disabled")); + _playlistSyncer!.SetEnabled(_settings.SyncPlaylist); + await _playlistSyncer.FetchDatabase(); + } + + if (old.SyncProfile != _settings.SyncProfile) + { + // TODO: Replace with Logger + Console.WriteLine("Profile Syncer: " + (_settings.SyncHistory ? "Enabled" : "Disabled")); + _profileSyncer!.SetEnabled(_settings.SyncProfile); + await _profileSyncer.FetchDatabase(); + } + + if (old.SyncSearchHistory != _settings.SyncSearchHistory) + { + // TODO: Replace with Logger + Console.WriteLine("Search History Syncer: " + (_settings.SyncHistory ? "Enabled" : "Disabled")); + _searchHistorySyncer!.SetEnabled(_settings.SyncSearchHistory); + await _searchHistorySyncer.FetchDatabase(); + } + + if (old.SyncSettings != _settings.SyncSettings) + { + // TODO: Replace with Logger + Console.WriteLine("Settings Syncer: " + (_settings.SyncHistory ? "Enabled" : "Disabled")); + _settingSyncer!.SetEnabled(_settings.SyncSettings); + await _settingSyncer.FetchDatabase(); + } _semaphoreSlim.Release(); }