From 5887bc0961eb345b1df713d95ccf358a8a630f09 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Wed, 30 Jul 2025 12:19:53 -0500 Subject: [PATCH 1/2] Updated Syncer Added interface for Syncer class. Changed IsDirty from Property to Function Moved order for reading in initial database. First will fetch from the REST Api, then it will read in the database stored locally. Changed logic behind reading and fetching database. Fetching the database from the REST Api will mark internally that it is dirty, and force syncing. If an entry exists in our cache, and is equal, then we continue through, otherwise we remove the old entry, and use the new entry. --- FreeTubeSyncer/REST/Syncer.cs | 47 ++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/FreeTubeSyncer/REST/Syncer.cs b/FreeTubeSyncer/REST/Syncer.cs index 13758f9..f61be58 100644 --- a/FreeTubeSyncer/REST/Syncer.cs +++ b/FreeTubeSyncer/REST/Syncer.cs @@ -11,7 +11,16 @@ using RestSharp; namespace FreeTubeSyncer.REST; -public class Syncer where T : class, IDataModel, new() +public interface ISyncer +{ + Task ReadDatabase(); + Task FetchDatabase(); + void HandleDatabaseChange(string dbName, string entryObject); + void Sync(); + bool IsDirty(); +} + +public class Syncer : ISyncer where T : class, IDataModel, new() { private List _entries = new List(); private RestClient _client; @@ -19,21 +28,23 @@ public class Syncer where T : class, IDataModel, new() private string _dbName; private string _restEndpoint; - public bool IsDirty = false; + private bool _isDirty = false; public Syncer(DBSyncWatcher watcher, string dbPath, string dbName, string restEndpoint) { watcher.WatchFiles[dbName] = typeof(T); watcher.OnDatabaseChange += HandleDatabaseChange; - _client = new RestClient(new RestClientOptions("http://localhost:5183")); + _client = new RestClient(new RestClientOptions("http://192.168.1.30:5050")); _dbPath = dbPath; _dbName = dbName; _restEndpoint = restEndpoint; - ReadDatabase().Wait(); FetchDatabase().Wait(); + ReadDatabase().Wait(); } - private async Task ReadDatabase() + public bool IsDirty() => _isDirty; + + public async Task ReadDatabase() { var lines = File.ReadAllLines(_dbPath); foreach (var entry in lines) @@ -60,20 +71,26 @@ public class Syncer where T : class, IDataModel, new() } } - private async Task FetchDatabase() + public async Task FetchDatabase() { - var entries = await _client.GetAsync>(_restEndpoint); + var entries = await _client.GetAsync>(_restEndpoint); if (entries == null) return; foreach (var entry in entries) { if (_entries.Any(x => x.EqualId(entry.Id()))) + { + var data = _entries.First(x => x.EqualId(entry.Id())); + + if (data.Equals(entry)) continue; + _entries.RemoveAll(x => x.EqualId(entry.Id())); - + } _entries.Add(entry); + _isDirty = true; } } - private async void HandleDatabaseChange(string dbName, string entryObject) + public async void HandleDatabaseChange(string dbName, string entryObject) { if (dbName != _dbName) return; @@ -92,16 +109,22 @@ public class Syncer where T : class, IDataModel, new() if (entry == null) return; entry.MarshalData(entry.Id(), entryObject); + if (_entries.Any(x => x.EqualId(entry.Id()))) + { + var data = _entries.First(x => x.EqualId(entry.Id())); + if (data.Equals(entry)) return; + _entries.RemoveAll(x => x.EqualId(entry.Id())); + } + _entries.Add(entry); await _client.PostJsonAsync(_restEndpoint, entry); - IsDirty = true; } public void Sync() { - if (!IsDirty) + if (!_isDirty) return; Console.WriteLine($"Syncing {_dbPath}..."); var json = new List(); @@ -109,6 +132,6 @@ public class Syncer where T : class, IDataModel, new() json.Add(entry.JsonData()); File.WriteAllLines(_dbPath, json); Console.WriteLine($"Updated {_dbPath}."); - IsDirty = false; + _isDirty = false; } } \ No newline at end of file From 58e046c1f0605316f4a5e7b1c1fabec0e2d4938f Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Wed, 30 Jul 2025 12:20:50 -0500 Subject: [PATCH 2/2] Updated Program Now utilizing syncers in an Array for each checking of IsDirty() or not, and running code based upon the state of the syncers. May clean this up more. Added polling of the database to see if there's anything new to sync locally. --- FreeTubeSyncer/Program.cs | 58 +++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/FreeTubeSyncer/Program.cs b/FreeTubeSyncer/Program.cs index 24adb90..f5fd8c8 100644 --- a/FreeTubeSyncer/Program.cs +++ b/FreeTubeSyncer/Program.cs @@ -1,7 +1,9 @@ using Avalonia; using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using FreeTubeSyncer.Library; @@ -50,23 +52,49 @@ class Program Syncer? profileSyncer = null, Syncer? searchHistorySyncer = null, Syncer? settingsSyncer = null) { + var syncers = new List() + { + historySyncer, + playlistSyncer, + profileSyncer, + searchHistorySyncer, + settingsSyncer + }; + var lastTime = DateTime.Now; while (true) { - Thread.Sleep(100); - if (Process.GetProcessesByName("FreeTube").Length > 0) continue; - Console.WriteLine("FreeTube has closed, we're going to try and update."); - Thread.Sleep(1500); - - if (historySyncer is { IsDirty: true }) - historySyncer.Sync(); - if (playlistSyncer is { IsDirty: true }) - playlistSyncer.Sync(); - if (profileSyncer is { IsDirty: true}) - profileSyncer.Sync(); - if (searchHistorySyncer is { IsDirty: true}) - searchHistorySyncer.Sync(); - if (settingsSyncer is { IsDirty: true}) - settingsSyncer.Sync(); + if (syncers.Any(x => x != null && x.IsDirty() )) + { + Thread.Sleep(100); + if (lastTime - DateTime.Now > TimeSpan.FromSeconds(30)) + { + foreach (var syncer in syncers) + syncer.FetchDatabase().Wait(); + lastTime = DateTime.Now; + } + if (Process.GetProcessesByName("FreeTube").Length > 0) continue; + Console.WriteLine("FreeTube has closed and we have updates, we're going to try and update."); + Thread.Sleep(1500); + + if (historySyncer != null && historySyncer.IsDirty()) + historySyncer.Sync(); + if (playlistSyncer != null && playlistSyncer.IsDirty()) + playlistSyncer.Sync(); + if (profileSyncer != null && profileSyncer.IsDirty()) + profileSyncer.Sync(); + if (searchHistorySyncer != null && searchHistorySyncer.IsDirty()) + searchHistorySyncer.Sync(); + if (settingsSyncer != null && settingsSyncer.IsDirty()) + settingsSyncer.Sync(); + } + else + { + Thread.Sleep(100); + if (lastTime - DateTime.Now <= TimeSpan.FromSeconds(30)) continue; + foreach (var syncer in syncers) + syncer.FetchDatabase().Wait(); + lastTime = DateTime.Now; + } } } // public static void Main(string[] args) => BuildAvaloniaApp()