Compare commits
6 commits
ddf50a3052
...
6fb47905c0
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fb47905c0 | |||
| b0ac6c1b7b | |||
| 56432cd33d | |||
| 7099e31ff5 | |||
| e6236b8a5a | |||
| ec55cf2f11 |
8 changed files with 349 additions and 119 deletions
|
|
@ -1,22 +1,24 @@
|
|||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sukiUi="clr-namespace:SukiUI;assembly=SukiUI"
|
||||
x:Class="FreeTubeSyncer.App"
|
||||
RequestedThemeVariant="Default">
|
||||
RequestedThemeVariant="Dark">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<sukiUi:SukiTheme ThemeColor="Blue" />
|
||||
</Application.Styles>
|
||||
|
||||
<TrayIcon.Icons>
|
||||
<TrayIcons>
|
||||
<TrayIcon Icon="/Assets/freetube.png"
|
||||
ToolTipText="FreeTube Syncer">
|
||||
ToolTipText="FreeTube Syncer"
|
||||
Clicked="TrayIcon_OnClicked">
|
||||
<TrayIcon.Menu>
|
||||
<NativeMenu>
|
||||
<NativeMenuItem Header="Show Settings"/>
|
||||
<NativeMenuItem Header="Show Settings" Click="ShowSettings_OnClick"/>
|
||||
<NativeMenuItemSeparator/>
|
||||
<NativeMenuItem Header="Quit"/>
|
||||
<NativeMenuItem Header="Quit" Click="Quit_OnClick"/>
|
||||
</NativeMenu>
|
||||
</TrayIcon.Menu>
|
||||
</TrayIcon>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using FreeTubeSyncer.Library;
|
||||
using FreeTubeSyncer.Models;
|
||||
using FreeTubeSyncer.Models.DatabaseModels;
|
||||
using FreeTubeSyncer.REST;
|
||||
|
||||
namespace FreeTubeSyncer;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
private DBSyncWatcher _watcher;
|
||||
private DBSyncWatcher? _watcher;
|
||||
private List<ISyncer>? _syncers;
|
||||
private Syncer<History>? _historySyncer;
|
||||
private Syncer<Playlist>? _playlistSyncer;
|
||||
private Syncer<Profile>? _profileSyncer;
|
||||
private Syncer<SearchHistory>? _searchHistorySyncer;
|
||||
private Syncer<Setting>? _settingSyncer;
|
||||
private bool _isRunning = true;
|
||||
private Task? _watcherTask;
|
||||
private DateTime _lastClick = DateTime.MinValue;
|
||||
private AppSettings? _settings;
|
||||
private string? _oldSettings;
|
||||
private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
private TimeSpan _checkInterval;
|
||||
|
||||
public event EventHandler? SettingsChanged;
|
||||
|
||||
public static App GetApp() => (App)App.Current!;
|
||||
public static ClassicDesktopStyleApplicationLifetime GetDesktop() => (ClassicDesktopStyleApplicationLifetime)App.Current!.ApplicationLifetime!;
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
|
|
@ -21,9 +46,8 @@ public partial class App : Application
|
|||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
//desktop.MainWindow = new MainWindow();
|
||||
var path = "";
|
||||
if (OperatingSystem.IsWindows())
|
||||
if (OperatingSystem.IsWindows() || OperatingSystem.IsMacOS())
|
||||
path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FreeTube");
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
|
|
@ -37,17 +61,187 @@ public partial class App : Application
|
|||
Console.WriteLine("Failed to find Path for FreeTube!");
|
||||
}
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FreeTube");
|
||||
|
||||
LoadSettings();
|
||||
_checkInterval = TimeSpan.FromSeconds(_settings!.CheckInterval);
|
||||
|
||||
_watcher = new DBSyncWatcher(path);
|
||||
_watcher.WatchFiles.Add("history.db", typeof(History));
|
||||
_watcher.WatchFiles.Add("playlist.db", typeof(Playlist));
|
||||
_watcher.WatchFiles.Add("profiles.db", typeof(Profile));
|
||||
_watcher.WatchFiles.Add("search-history.db", typeof(SearchHistory));
|
||||
_watcher.WatchFiles.Add("settings.db", typeof(Setting));
|
||||
_historySyncer = new Syncer<History>(_watcher, Path.Join(path, "history.db"), "history.db", _settings.RestBaseUrl, "/history");
|
||||
_playlistSyncer = new Syncer<Playlist>(_watcher, Path.Join(path, "playlists.db"), "playlists.db", _settings.RestBaseUrl, "/playlist");
|
||||
_profileSyncer = new Syncer<Profile>(_watcher, Path.Join(path, "profiles.db"), "profiles.db", _settings.RestBaseUrl, "/profile");
|
||||
_searchHistorySyncer = new Syncer<SearchHistory>(_watcher, Path.Join(path, "search-history.db"), "search-history.db", _settings.RestBaseUrl, "/searchHistory");
|
||||
_settingSyncer = new Syncer<Setting>(_watcher, Path.Join(path, "settings.db"), "settings.db", _settings.RestBaseUrl, "/settings");
|
||||
_syncers =
|
||||
[
|
||||
_historySyncer,
|
||||
_playlistSyncer,
|
||||
_profileSyncer,
|
||||
_searchHistorySyncer,
|
||||
_settingSyncer
|
||||
];
|
||||
SettingsChanged += HandleSettingsChanged;
|
||||
_watcherTask = Task.Run(SyncMonitor);
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
public void StampSettings() => _oldSettings = JsonSerializer.Serialize(_settings);
|
||||
|
||||
public void ResetSettings()
|
||||
{
|
||||
var @new = JsonSerializer.Deserialize<AppSettings>(_oldSettings!);
|
||||
_settings!.RestBaseUrl = @new!.RestBaseUrl;
|
||||
_settings.CheckInterval = @new.CheckInterval;
|
||||
_settings.SyncHistory = @new.SyncHistory;
|
||||
_settings.SyncPlaylist = @new.SyncPlaylist;
|
||||
_settings.SyncProfile = @new.SyncProfile;
|
||||
_settings.SyncSearchHistory = @new.SyncSearchHistory;
|
||||
_settings.SyncSettings = @new.SyncSettings;
|
||||
}
|
||||
|
||||
public void SaveSettings()
|
||||
{
|
||||
var path = GetSettingsPath();
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
var dir = Path.GetDirectoryName(path);
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
File.WriteAllText(path, JsonSerializer.Serialize(_settings));
|
||||
SettingsChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void LoadSettings()
|
||||
{
|
||||
var path = GetSettingsPath();
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
_settings = new AppSettings();
|
||||
return;
|
||||
}
|
||||
var data = File.ReadAllText(path);
|
||||
_settings = JsonSerializer.Deserialize<AppSettings>(data);
|
||||
}
|
||||
|
||||
private string GetSettingsPath() => OperatingSystem.IsLinux()
|
||||
? Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FreeTubeSyncer", "settings.json")
|
||||
: Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "FreeTubeSyncer", "settings.json");
|
||||
|
||||
private async Task SyncMonitor()
|
||||
{
|
||||
while (_isRunning)
|
||||
{
|
||||
await _semaphoreSlim.WaitAsync();
|
||||
if (!await _syncers![0].PingApi())
|
||||
{
|
||||
_semaphoreSlim.Release();
|
||||
await Task.Delay(5000);
|
||||
continue;
|
||||
}
|
||||
foreach (var syncer in _syncers!)
|
||||
{
|
||||
await syncer.FetchDatabase();
|
||||
}
|
||||
|
||||
_semaphoreSlim.Release();
|
||||
break;
|
||||
}
|
||||
|
||||
var lastCheck = DateTime.Now;
|
||||
while (_isRunning)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
|
||||
var sinceLastCheck = DateTime.Now - lastCheck;
|
||||
if (sinceLastCheck.TotalSeconds > _checkInterval.TotalSeconds)
|
||||
{
|
||||
await _semaphoreSlim.WaitAsync();
|
||||
var start = DateTime.Now;
|
||||
// TODO: Replace with Logger
|
||||
Console.WriteLine("Checking for updates...");
|
||||
foreach (var syncer in _syncers)
|
||||
await syncer.FetchDatabase();
|
||||
lastCheck = DateTime.Now;
|
||||
var end = DateTime.Now - start;
|
||||
_semaphoreSlim.Release();
|
||||
// TODO: Replace with Logger
|
||||
Console.WriteLine($"Check Completed. Total Time: {end}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_syncers.Any(x => x.IsDirty())) continue;
|
||||
|
||||
var procs = Process.GetProcessesByName("FreeTube");
|
||||
if (procs.Length > 0) continue;
|
||||
// TODO: Replace with Logger
|
||||
Console.WriteLine("FreeTube closed, and we have writes to make...");
|
||||
await Task.Delay(1500);
|
||||
|
||||
await _semaphoreSlim.WaitAsync();
|
||||
var syncStart = DateTime.Now;
|
||||
foreach (var syncer in _syncers)
|
||||
syncer.Sync();
|
||||
var syncEnd = DateTime.Now - syncStart;
|
||||
_semaphoreSlim.Release();
|
||||
// TODO: Replace with Logger
|
||||
Console.WriteLine($"Sync completed in {syncEnd}.");
|
||||
}
|
||||
}
|
||||
|
||||
private async void HandleSettingsChanged(object? sender, EventArgs e)
|
||||
{
|
||||
await _semaphoreSlim.WaitAsync();
|
||||
var old = JsonSerializer.Deserialize<AppSettings>(_oldSettings!);
|
||||
if (_settings!.RestBaseUrl != old!.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);
|
||||
_semaphoreSlim.Release();
|
||||
}
|
||||
|
||||
private void ShowSettings_OnClick(object? sender, EventArgs e)
|
||||
{
|
||||
if (App.Current!.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return;
|
||||
if (desktop.MainWindow is null)
|
||||
{
|
||||
desktop.MainWindow = new MainWindow()
|
||||
{
|
||||
DataContext = _settings
|
||||
};
|
||||
}
|
||||
StampSettings();
|
||||
desktop.MainWindow!.Show();
|
||||
}
|
||||
|
||||
private void Quit_OnClick(object? sender, EventArgs e)
|
||||
{
|
||||
if (App.Current!.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return;
|
||||
_semaphoreSlim.Wait();
|
||||
_isRunning = false;
|
||||
_semaphoreSlim.Release();
|
||||
_watcherTask?.Wait();
|
||||
desktop.Shutdown();
|
||||
}
|
||||
|
||||
private void TrayIcon_OnClicked(object? sender, EventArgs e)
|
||||
{
|
||||
var clicked = DateTime.Now;
|
||||
if (_lastClick == DateTime.MinValue || (clicked - _lastClick).TotalMilliseconds > TimeSpan.FromMilliseconds(500).TotalMilliseconds)
|
||||
_lastClick = clicked;
|
||||
else
|
||||
{
|
||||
_lastClick = DateTime.MinValue;
|
||||
ShowSettings_OnClick(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,9 @@
|
|||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||
<PackageReference Include="SukiUI" Version="6.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,51 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<suki:SukiWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
xmlns:suki="https://github.com/kikipoulet/SukiUI"
|
||||
xmlns:vm="clr-namespace:FreeTubeSyncer.Models"
|
||||
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="345"
|
||||
Width="400" Height="345"
|
||||
x:Class="FreeTubeSyncer.MainWindow"
|
||||
x:DataType="vm:AppSettings"
|
||||
BackgroundStyle="GradientDarker"
|
||||
CanResize="False"
|
||||
CanMaximize="False"
|
||||
Title="FreeTubeSyncer">
|
||||
Welcome to Avalonia!
|
||||
</Window>
|
||||
|
||||
<StackPanel Orientation="Vertical" Margin="10" Spacing="5">
|
||||
<Label Content="Settings" FontSize="24"/>
|
||||
<Separator/>
|
||||
|
||||
<Grid
|
||||
ColumnDefinitions="182,*"
|
||||
RowDefinitions="*,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Text="REST API Backend Server: " FontWeight="Bold"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Watermark="http://localhost:8080" Text="{Binding RestBaseUrl, Mode=TwoWay}"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Text="Refresh Interval: " FontWeight="Bold"/>
|
||||
<NumericUpDown Grid.Row="1" Grid.Column="1" Watermark="30" suki:NumericUpDownExtensions.Unit="seconds" FormatString="N0" Value="{Binding CheckInterval, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
<Grid
|
||||
ColumnDefinitions="170,*"
|
||||
RowDefinitions="*,*,*">
|
||||
<ToggleSwitch Grid.Row="0" Grid.Column="0" IsPressed="{Binding SyncHistory, Mode=TwoWay}" OnContent="Sync History" />
|
||||
<ToggleSwitch Grid.Row="0" Grid.Column="1" IsPressed="{Binding SyncPlaylist, Mode=TwoWay}" OnContent="Sync Playlists"/>
|
||||
<ToggleSwitch Grid.Row="1" Grid.Column="0" IsPressed="{Binding SyncProfile, Mode=TwoWay}" OnContent="Sync Profiles"/>
|
||||
<ToggleSwitch Grid.Row="1" Grid.Column="1" IsPressed="{Binding SyncSearchHistory, Mode=TwoWay}" OnContent="Sync Search History"/>
|
||||
<ToggleSwitch Grid.Row="2" Grid.Column="0" IsPressed="{Binding SyncSettings, Mode=TwoWay}" OnContent="Sync Settings"/>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10">
|
||||
<Button
|
||||
IsEnabled="{Binding SettingsDirty}"
|
||||
Classes="Flat Accent"
|
||||
Click="SaveSettings_OnClick"
|
||||
Content="Save"/>
|
||||
<Button
|
||||
IsEnabled="True"
|
||||
Classes="Danger"
|
||||
Click="CloseWindow_OnClick"
|
||||
Content="Cancel"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</suki:SukiWindow>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,29 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using SukiUI.Controls;
|
||||
|
||||
namespace FreeTubeSyncer;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
public partial class MainWindow : SukiWindow
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Closing += (s, e) =>
|
||||
{
|
||||
((SukiWindow)s).Hide();
|
||||
e.Cancel = true;
|
||||
};
|
||||
}
|
||||
|
||||
private void SaveSettings_OnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
App.GetApp().SaveSettings();
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void CloseWindow_OnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
App.GetApp().ResetSettings();
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
27
FreeTubeSyncer/Models/AppSetting.cs
Normal file
27
FreeTubeSyncer/Models/AppSetting.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace FreeTubeSyncer.Models;
|
||||
|
||||
public partial class AppSettings : ObservableObject
|
||||
{
|
||||
[ObservableProperty] [property: JsonInclude] private string _restBaseUrl = "http://127.0.0.1:8080";
|
||||
[ObservableProperty] [property: JsonInclude] private int _checkInterval = 30;
|
||||
[ObservableProperty] [property: JsonInclude] private bool _syncHistory = true;
|
||||
[ObservableProperty] [property: JsonInclude] private bool _syncPlaylist = true;
|
||||
[ObservableProperty] [property: JsonInclude] private bool _syncProfile = true;
|
||||
[ObservableProperty] [property: JsonInclude] private bool _syncSearchHistory = true;
|
||||
[ObservableProperty] [property: JsonInclude] private bool _syncSettings = true;
|
||||
[ObservableProperty] [property: JsonIgnore] private bool _settingsDirty = false;
|
||||
|
||||
public AppSettings()
|
||||
{
|
||||
PropertyChanged += (sender, args) =>
|
||||
{
|
||||
if (args.PropertyName == nameof(SettingsDirty))
|
||||
return;
|
||||
|
||||
SettingsDirty = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -18,100 +18,7 @@ class Program
|
|||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
GlobalJsonOptions.Options.Converters.Add(new StringToLongJsonConverter(false));
|
||||
var paths = new string[]
|
||||
{
|
||||
Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config/FreeTube/"),
|
||||
Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
||||
".var/app/io.freetubeapp.FreeTube/config/FreeTube")
|
||||
};
|
||||
|
||||
var path = "";
|
||||
|
||||
foreach (var tpath in paths)
|
||||
{
|
||||
if (!Directory.Exists(tpath)) continue;
|
||||
path = tpath;
|
||||
break;
|
||||
}
|
||||
var dbWatcher = new DBSyncWatcher(path);
|
||||
var historySyncer = new Syncer<History>(dbWatcher, Path.Join(path, "history.db"), "history.db", "/history");
|
||||
var playlistSyncer = new Syncer<Playlist>(dbWatcher, Path.Join(path, "playlists.db"), "playlists.db", "/playlist");
|
||||
var profileSyncer = new Syncer<Profile>(dbWatcher, Path.Join(path, "profiles.db"), "profiles.db", "/profile");
|
||||
var searchHistorySyncer = new Syncer<SearchHistory>(dbWatcher, Path.Join(path, "search-history.db"), "search-history.db", "/searchHistory");
|
||||
var settingsSyncer = new Syncer<Setting>(dbWatcher, Path.Join(path, "settings.db"), "settings.db", "/settings");
|
||||
|
||||
Task.Run(() => CheckCanSync(historySyncer, playlistSyncer, profileSyncer, searchHistorySyncer, settingsSyncer));
|
||||
Console.WriteLine("Watching databases... Press return to exit...");
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
private static void CheckCanSync(Syncer<History>? historySyncer = null, Syncer<Playlist>? playlistSyncer = null,
|
||||
Syncer<Profile>? profileSyncer = null, Syncer<SearchHistory>? searchHistorySyncer = null,
|
||||
Syncer<Setting>? settingsSyncer = null)
|
||||
{
|
||||
var syncers = new List<ISyncer>()
|
||||
{
|
||||
historySyncer,
|
||||
playlistSyncer,
|
||||
profileSyncer,
|
||||
searchHistorySyncer,
|
||||
settingsSyncer
|
||||
};
|
||||
var lastTime = DateTime.Now;
|
||||
var checkInterval = TimeSpan.FromSeconds(30);
|
||||
while (true)
|
||||
{
|
||||
if (syncers.Any(x => x != null && x.IsDirty() ))
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
var lastCheck = DateTime.Now - lastTime;
|
||||
if (lastCheck > checkInterval)
|
||||
{
|
||||
var start = DateTime.Now;
|
||||
Console.WriteLine("Checking for updates...");
|
||||
foreach (var syncer in syncers)
|
||||
syncer.FetchDatabase().Wait();
|
||||
lastTime = DateTime.Now;
|
||||
var end = DateTime.Now - start;
|
||||
Console.WriteLine($"Check completed. Total Time: {end}");
|
||||
}
|
||||
|
||||
var procs = Process.GetProcessesByName("FreeTube");
|
||||
if (procs.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);
|
||||
var lastCheck = DateTime.Now - lastTime;
|
||||
if (lastCheck < checkInterval) continue;
|
||||
var start = DateTime.Now;
|
||||
Console.WriteLine("Checking for updates...");
|
||||
foreach (var syncer in syncers)
|
||||
syncer.FetchDatabase().Wait();
|
||||
lastTime = DateTime.Now;
|
||||
var end = DateTime.Now - start;
|
||||
Console.WriteLine($"Check completed. Total Time: {end}");
|
||||
}
|
||||
}
|
||||
}
|
||||
// public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
// .StartWithClassicDesktopLifetime(args);
|
||||
public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
|
@ -19,6 +20,13 @@ public interface ISyncer
|
|||
void HandleDatabaseChange(string dbName, string entryObject);
|
||||
void Sync();
|
||||
bool IsDirty();
|
||||
void Enable();
|
||||
void Disable();
|
||||
bool IsEnabled();
|
||||
|
||||
void UpdateBaseUrl(string baseUrl);
|
||||
void SetEnabled(bool enabled);
|
||||
Task<bool> PingApi();
|
||||
}
|
||||
|
||||
public class Syncer<T> : ISyncer where T : class, IDataModel, new()
|
||||
|
|
@ -32,23 +40,50 @@ public class Syncer<T> : ISyncer where T : class, IDataModel, new()
|
|||
|
||||
private bool _isDirty = false;
|
||||
private bool _syncing = false;
|
||||
private bool _enabled = true;
|
||||
|
||||
public Syncer(DBSyncWatcher watcher, string dbPath, string dbName, string restEndpoint)
|
||||
public Syncer(DBSyncWatcher watcher, string dbPath, string dbName, string restBaseUrl, string restEndpoint)
|
||||
{
|
||||
_watcher = watcher;
|
||||
_watcher.WatchFiles[dbName] = typeof(T);
|
||||
_watcher.OnDatabaseChange += HandleDatabaseChange;
|
||||
_client = new RestClient(new RestClientOptions("http://192.168.1.30:5050"));
|
||||
_client = new RestClient(new RestClientOptions(restBaseUrl));
|
||||
_dbPath = dbPath;
|
||||
_dbName = dbName;
|
||||
_restEndpoint = restEndpoint;
|
||||
FetchDatabase().Wait();
|
||||
}
|
||||
|
||||
public bool IsDirty() => _isDirty;
|
||||
public bool IsEnabled() => _enabled;
|
||||
public void Enable() => _enabled = true;
|
||||
public void Disable() => _enabled = false;
|
||||
public void SetEnabled(bool enabled) => _enabled = enabled;
|
||||
|
||||
public void UpdateBaseUrl(string baseUrl)
|
||||
{
|
||||
_client.Dispose();
|
||||
_client = new RestClient(new RestClientOptions(baseUrl));
|
||||
}
|
||||
|
||||
public async Task<bool> PingApi()
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = await _client.ExecuteHeadAsync(new RestRequest("/ping"));
|
||||
if (res.StatusCode == HttpStatusCode.NotFound)
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task ReadDatabase()
|
||||
{
|
||||
if (!_enabled) return;
|
||||
var lines = File.ReadAllLines(_dbPath);
|
||||
foreach (var entry in lines)
|
||||
{
|
||||
|
|
@ -76,6 +111,7 @@ public class Syncer<T> : ISyncer where T : class, IDataModel, new()
|
|||
|
||||
public async Task FetchDatabase()
|
||||
{
|
||||
if (!_enabled) return;
|
||||
var entries = await _client.GetAsync<List<T>>(_restEndpoint);
|
||||
if (entries == null) return;
|
||||
foreach (var entry in entries)
|
||||
|
|
@ -98,6 +134,7 @@ public class Syncer<T> : ISyncer where T : class, IDataModel, new()
|
|||
|
||||
public async void HandleDatabaseChange(string dbName, string entryObject)
|
||||
{
|
||||
if (!_enabled) return;
|
||||
if (dbName != _dbName)
|
||||
return;
|
||||
|
||||
|
|
@ -133,6 +170,7 @@ public class Syncer<T> : ISyncer where T : class, IDataModel, new()
|
|||
|
||||
public void Sync()
|
||||
{
|
||||
if (!_enabled) return;
|
||||
if (!_isDirty)
|
||||
return;
|
||||
_syncing = true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue