Extend uploader profiles, filters, and diagnostics
This commit is contained in:
@@ -61,6 +61,13 @@
|
||||
<Border x:Name="AdvancedPanel" Padding="12" Classes="card accent" IsVisible="False">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Text="Erweiterte Einstellungen" FontWeight="SemiBold" />
|
||||
<ToggleSwitch x:Name="SettingsUnlockToggle" Content="Einstellungen entsperren" Checked="SettingsUnlockToggle_Changed" Unchecked="SettingsUnlockToggle_Changed" />
|
||||
<TextBlock Text="Profile" />
|
||||
<ComboBox x:Name="ProfilesBox" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Button x:Name="LoadProfileButton" Content="Profil laden" Click="LoadProfileButton_Click" Classes="secondary" />
|
||||
<Button x:Name="SaveProfileButton" Content="Profil speichern" Click="SaveProfileButton_Click" Classes="secondary" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="Basis-URL" />
|
||||
<TextBox x:Name="BaseUrlBox" Watermark="https://fotospiel.app" />
|
||||
<TextBlock Text="Max. parallele Uploads" />
|
||||
@@ -75,6 +82,12 @@
|
||||
<TextBox x:Name="IncludePatternsBox" Watermark="*.jpg;*.jpeg;*.png" />
|
||||
<TextBlock Text="Dateien ausschliessen (optional)" />
|
||||
<TextBox x:Name="ExcludePatternsBox" Watermark="*_preview*;*.tmp" />
|
||||
<TextBlock Text="Antwort-Format (optional)" />
|
||||
<ComboBox x:Name="ResponseFormatBox" SelectedIndex="0">
|
||||
<ComboBoxItem Content="Auto" />
|
||||
<ComboBoxItem Content="JSON" />
|
||||
<ComboBoxItem Content="XML" />
|
||||
</ComboBox>
|
||||
<TextBlock Text="Manuelle Zugangsdaten (optional)" FontWeight="SemiBold" Margin="0,8,0,0" />
|
||||
<TextBlock Text="Diese Felder ueberschreiben den Verbindungscode." Classes="subtitle" TextWrapping="Wrap" />
|
||||
<TextBlock Text="Upload-URL" />
|
||||
@@ -106,9 +119,12 @@
|
||||
<TextBlock x:Name="EventNameText" Text="Event: —" TextWrapping="Wrap" />
|
||||
<TextBlock x:Name="BaseUrlText" Text="Basis-URL: —" TextWrapping="Wrap" />
|
||||
<TextBlock x:Name="VersionText" Text="App-Version: —" />
|
||||
<TextBlock x:Name="ConnectExpiryText" Text="Verbindungscode: —" TextWrapping="Wrap" />
|
||||
<TextBlock x:Name="FolderHealthText" Text="Ordner: —" TextWrapping="Wrap" />
|
||||
<TextBlock x:Name="DiskFreeText" Text="Freier Speicher: —" TextWrapping="Wrap" />
|
||||
<TextBlock x:Name="LastSeenText" Text="Letzte Datei: —" TextWrapping="Wrap" />
|
||||
<TextBlock x:Name="LastErrorText" Text="Letzter Fehler: —" TextWrapping="Wrap" />
|
||||
<Button x:Name="LogCopyButton" Content="Log kopieren" Click="LogCopyButton_Click" Classes="secondary" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
@@ -128,7 +144,10 @@
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Button x:Name="RetryFailedButton" Content="Fehlgeschlagene erneut senden" Click="RetryFailedButton_Click" IsEnabled="False" Classes="secondary" />
|
||||
<Button x:Name="ClearFailedButton" Content="Fehlerliste leeren" Click="ClearFailedButton_Click" IsEnabled="False" Classes="secondary" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
@@ -35,6 +35,7 @@ public partial class MainWindow : Window
|
||||
private DateTimeOffset? _lastSuccessAt;
|
||||
private bool _advancedVisible;
|
||||
private readonly DispatcherTimer _liveTimer = new();
|
||||
private readonly List<string> _logBuffer = new();
|
||||
|
||||
public ObservableCollection<UploadItem> RecentUploads { get; } = new();
|
||||
|
||||
@@ -130,12 +131,15 @@ public partial class MainWindow : Window
|
||||
_settings.Password = response.Data.Password;
|
||||
_settings.ResponseFormat = response.Data.ResponseFormat;
|
||||
_settings.EventName = response.Data.EventName;
|
||||
_settings.ConnectExpiresAt = response.Data.ExpiresAt;
|
||||
_settingsStore.Save(_settings);
|
||||
|
||||
StatusText.Text = "Verbunden. Upload bereit.";
|
||||
AppendLog("Verbunden mit Event.");
|
||||
PickFolderButton.IsEnabled = true;
|
||||
TestUploadButton.IsEnabled = true;
|
||||
ReconnectButton.IsEnabled = true;
|
||||
UpdateAdvancedLockState();
|
||||
UpdateDiagnostics();
|
||||
StartUploadPipelineIfReady();
|
||||
}
|
||||
@@ -177,9 +181,11 @@ public partial class MainWindow : Window
|
||||
UploadTempoBox.SelectedIndex = ResolveUploadTempoIndex(_settings.UploadDelayMs);
|
||||
IncludePatternsBox.Text = _settings.IncludePatterns ?? string.Empty;
|
||||
ExcludePatternsBox.Text = _settings.ExcludePatterns ?? string.Empty;
|
||||
ResponseFormatBox.SelectedIndex = ResolveResponseFormatIndex(_settings.ResponseFormat);
|
||||
ManualUploadUrlBox.Text = _settings.UploadUrl ?? string.Empty;
|
||||
ManualUsernameBox.Text = _settings.Username ?? string.Empty;
|
||||
ManualPasswordBox.Text = string.Empty;
|
||||
SettingsUnlockToggle.IsChecked = false;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_settings.UploadUrl))
|
||||
{
|
||||
@@ -194,6 +200,8 @@ public partial class MainWindow : Window
|
||||
UpdateFolderHealth();
|
||||
UpdateDiagnostics();
|
||||
UpdateSteps();
|
||||
RefreshProfiles();
|
||||
UpdateAdvancedLockState();
|
||||
}
|
||||
|
||||
private void OnWindowOpened(object? sender, EventArgs e)
|
||||
@@ -263,6 +271,7 @@ public partial class MainWindow : Window
|
||||
return;
|
||||
}
|
||||
|
||||
RecordLastSeen(e.FullPath);
|
||||
_uploadService.Enqueue(e.FullPath, OnQueued);
|
||||
}
|
||||
|
||||
@@ -278,6 +287,7 @@ public partial class MainWindow : Window
|
||||
return;
|
||||
}
|
||||
|
||||
RecordLastSeen(e.FullPath);
|
||||
_uploadService.Enqueue(e.FullPath, OnQueued);
|
||||
}
|
||||
|
||||
@@ -299,6 +309,7 @@ public partial class MainWindow : Window
|
||||
UpdateUpload(path, UploadStatus.Queued);
|
||||
AddPendingUpload(path);
|
||||
UpdateStatusIfAllowed($"Wartet: {Path.GetFileName(path)}", false);
|
||||
AppendLog($"Wartet: {Path.GetFileName(path)}");
|
||||
UpdateCountersText();
|
||||
}
|
||||
|
||||
@@ -320,6 +331,7 @@ public partial class MainWindow : Window
|
||||
RemovePendingUpload(path);
|
||||
MarkUploaded(path);
|
||||
UpdateStatusIfAllowed($"Hochgeladen: {Path.GetFileName(path)}", false);
|
||||
AppendLog($"Hochgeladen: {Path.GetFileName(path)}");
|
||||
UpdateCountersText();
|
||||
UpdateLiveStatus();
|
||||
}
|
||||
@@ -333,6 +345,7 @@ public partial class MainWindow : Window
|
||||
RemovePendingUpload(path);
|
||||
UpdateStatusIfAllowed($"Upload fehlgeschlagen: {Path.GetFileName(path)}", true);
|
||||
SetLastError($"{Path.GetFileName(path)} – {message}");
|
||||
AppendLog($"Fehlgeschlagen: {Path.GetFileName(path)} – {message}");
|
||||
UpdateRetryButton();
|
||||
UpdateCountersText();
|
||||
}
|
||||
@@ -379,6 +392,7 @@ public partial class MainWindow : Window
|
||||
private void UpdateRetryButton()
|
||||
{
|
||||
RetryFailedButton.IsEnabled = _failedPaths.Count > 0;
|
||||
ClearFailedButton.IsEnabled = _failedPaths.Count > 0;
|
||||
}
|
||||
|
||||
private void RetryFailedButton_Click(object? sender, RoutedEventArgs e)
|
||||
@@ -401,6 +415,21 @@ public partial class MainWindow : Window
|
||||
UpdateCountersText();
|
||||
}
|
||||
|
||||
private void ClearFailedButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_failedPaths.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var cleared = _failedPaths.Count;
|
||||
_failedPaths.Clear();
|
||||
Interlocked.Add(ref _failedCount, -cleared);
|
||||
UpdateRetryButton();
|
||||
UpdateCountersText();
|
||||
UpdateStatusIfAllowed("Fehlerliste geleert.", false);
|
||||
}
|
||||
|
||||
private void UpdateSteps()
|
||||
{
|
||||
var hasCode = !string.IsNullOrWhiteSpace(_settings.UploadUrl);
|
||||
@@ -419,6 +448,11 @@ public partial class MainWindow : Window
|
||||
ReconnectButton.IsEnabled = enabled;
|
||||
}
|
||||
|
||||
private void SettingsUnlockToggle_Changed(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateAdvancedLockState();
|
||||
}
|
||||
|
||||
private void RestorePendingUploads()
|
||||
{
|
||||
EnsureSettingsCollections();
|
||||
@@ -553,6 +587,7 @@ public partial class MainWindow : Window
|
||||
_settings.UploadDelayMs = ResolveUploadDelay(UploadTempoBox.SelectedIndex);
|
||||
_settings.IncludePatterns = NormalizePatternInput(IncludePatternsBox.Text);
|
||||
_settings.ExcludePatterns = NormalizePatternInput(ExcludePatternsBox.Text);
|
||||
_settings.ResponseFormat = ResolveResponseFormat(ResponseFormatBox.SelectedIndex);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(manualUploadUrl))
|
||||
{
|
||||
@@ -577,6 +612,7 @@ public partial class MainWindow : Window
|
||||
UpdateFolderHealth();
|
||||
RestartUploadPipeline();
|
||||
UpdateSteps();
|
||||
UpdateAdvancedLockState();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_settings.UploadUrl))
|
||||
{
|
||||
@@ -678,6 +714,7 @@ public partial class MainWindow : Window
|
||||
{
|
||||
FolderHealthText.Text = "Ordner: —";
|
||||
DiskFreeText.Text = "Freier Speicher: —";
|
||||
LastSeenText.Text = "Letzte Datei: —";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -685,13 +722,14 @@ public partial class MainWindow : Window
|
||||
{
|
||||
FolderHealthText.Text = "Ordner: fehlt";
|
||||
DiskFreeText.Text = "Freier Speicher: —";
|
||||
LastSeenText.Text = "Letzte Datei: —";
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_ = Directory.EnumerateFileSystemEntries(folder).FirstOrDefault();
|
||||
FolderHealthText.Text = "Ordner: OK";
|
||||
FolderHealthText.Text = CanWriteToFolder(folder) ? "Ordner: OK (schreibbar)" : "Ordner: OK (nur lesen)";
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
@@ -702,7 +740,8 @@ public partial class MainWindow : Window
|
||||
FolderHealthText.Text = "Ordner: Fehler";
|
||||
}
|
||||
|
||||
DiskFreeText.Text = $"Freier Speicher: {FormatDiskFree(folder)}";
|
||||
DiskFreeText.Text = FormatDiskFree(folder);
|
||||
LastSeenText.Text = FormatLastSeen();
|
||||
}
|
||||
|
||||
private void UpdateLiveStatus()
|
||||
@@ -712,6 +751,7 @@ public partial class MainWindow : Window
|
||||
if (_lastSuccessAt is null)
|
||||
{
|
||||
LiveStatusText.Text = "Live: —";
|
||||
UpdateDiagnostics();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -719,6 +759,7 @@ public partial class MainWindow : Window
|
||||
var isLive = age <= TimeSpan.FromMinutes(5);
|
||||
var label = isLive ? "Live: Ja" : "Live: Nein";
|
||||
LiveStatusText.Text = $"{label} (letzter Upload {FormatRelativeAge(age)})";
|
||||
UpdateDiagnostics();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -747,17 +788,18 @@ public partial class MainWindow : Window
|
||||
var root = Path.GetPathRoot(folder);
|
||||
if (string.IsNullOrWhiteSpace(root))
|
||||
{
|
||||
return "—";
|
||||
return "Freier Speicher: —";
|
||||
}
|
||||
|
||||
var drive = new DriveInfo(root);
|
||||
if (!drive.IsReady)
|
||||
{
|
||||
return "—";
|
||||
return "Freier Speicher: —";
|
||||
}
|
||||
|
||||
var freeGb = drive.AvailableFreeSpace / (1024d * 1024d * 1024d);
|
||||
return $"{freeGb:0.0} GB";
|
||||
var label = freeGb < 5 ? "niedrig" : "ok";
|
||||
return $"Freier Speicher: {freeGb:0.0} GB ({label})";
|
||||
}
|
||||
|
||||
private string? ResolveUploadUrl(string? uploadUrl)
|
||||
@@ -816,6 +858,7 @@ public partial class MainWindow : Window
|
||||
EventNameText.Text = $"Event: {_settings.EventName ?? "—"}";
|
||||
BaseUrlText.Text = $"Basis-URL: {_settings.BaseUrl ?? "—"}";
|
||||
VersionText.Text = $"App-Version: {GetAppVersion()}";
|
||||
ConnectExpiryText.Text = FormatConnectExpiry();
|
||||
LastErrorText.Text = $"Letzter Fehler: {FormatLastError()}";
|
||||
});
|
||||
}
|
||||
@@ -866,6 +909,71 @@ public partial class MainWindow : Window
|
||||
{
|
||||
_settings.PendingUploads ??= new List<string>();
|
||||
_settings.UploadedFiles ??= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
_settings.Profiles ??= new List<PhotoboothProfile>();
|
||||
}
|
||||
|
||||
private void RecordLastSeen(string path)
|
||||
{
|
||||
_settings.LastSeenFile = Path.GetFileName(path);
|
||||
_settings.LastSeenAt = DateTimeOffset.Now.ToString("O");
|
||||
_settingsStore.Save(_settings);
|
||||
UpdateFolderHealth();
|
||||
}
|
||||
|
||||
private bool CanWriteToFolder(string folder)
|
||||
{
|
||||
try
|
||||
{
|
||||
var testFile = Path.Combine(folder, $".fotospiel-write-test-{Guid.NewGuid():N}.tmp");
|
||||
File.WriteAllText(testFile, "ok");
|
||||
File.Delete(testFile);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private string FormatLastSeen()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_settings.LastSeenAt) || string.IsNullOrWhiteSpace(_settings.LastSeenFile))
|
||||
{
|
||||
return "Letzte Datei: —";
|
||||
}
|
||||
|
||||
if (DateTimeOffset.TryParse(_settings.LastSeenAt, out var timestamp))
|
||||
{
|
||||
return $"Letzte Datei: {_settings.LastSeenFile} ({timestamp:HH:mm})";
|
||||
}
|
||||
|
||||
return $"Letzte Datei: {_settings.LastSeenFile}";
|
||||
}
|
||||
|
||||
private string FormatConnectExpiry()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_settings.ConnectExpiresAt))
|
||||
{
|
||||
return "Verbindungscode: —";
|
||||
}
|
||||
|
||||
if (!DateTimeOffset.TryParse(_settings.ConnectExpiresAt, out var expiry))
|
||||
{
|
||||
return "Verbindungscode: —";
|
||||
}
|
||||
|
||||
var remaining = expiry - DateTimeOffset.Now;
|
||||
if (remaining <= TimeSpan.Zero)
|
||||
{
|
||||
return "Verbindungscode: abgelaufen";
|
||||
}
|
||||
|
||||
if (remaining.TotalHours >= 1)
|
||||
{
|
||||
return $"Verbindungscode: {Math.Ceiling(remaining.TotalHours)} h gueltig";
|
||||
}
|
||||
|
||||
return $"Verbindungscode: {Math.Ceiling(remaining.TotalMinutes)} min gueltig";
|
||||
}
|
||||
|
||||
private string? ResolveTestUrl()
|
||||
@@ -926,6 +1034,31 @@ public partial class MainWindow : Window
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static string? ResolveResponseFormat(int selectedIndex)
|
||||
{
|
||||
return selectedIndex switch
|
||||
{
|
||||
1 => "json",
|
||||
2 => "xml",
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
private static int ResolveResponseFormatIndex(string? format)
|
||||
{
|
||||
if (string.Equals(format, "json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (string.Equals(format, "xml", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static string NormalizePatternInput(string? input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
@@ -1022,4 +1155,138 @@ public partial class MainWindow : Window
|
||||
|
||||
return patternIndex == pattern.Length;
|
||||
}
|
||||
|
||||
private void UpdateAdvancedLockState()
|
||||
{
|
||||
var connected = !string.IsNullOrWhiteSpace(_settings.UploadUrl);
|
||||
var unlocked = SettingsUnlockToggle?.IsChecked ?? false;
|
||||
var enabled = !connected || unlocked;
|
||||
|
||||
BaseUrlBox.IsEnabled = enabled;
|
||||
MaxUploadsBox.IsEnabled = enabled;
|
||||
UploadTempoBox.IsEnabled = enabled;
|
||||
IncludePatternsBox.IsEnabled = enabled;
|
||||
ExcludePatternsBox.IsEnabled = enabled;
|
||||
ResponseFormatBox.IsEnabled = enabled;
|
||||
ManualUploadUrlBox.IsEnabled = enabled;
|
||||
ManualUsernameBox.IsEnabled = enabled;
|
||||
ManualPasswordBox.IsEnabled = enabled;
|
||||
TestConnectionButton.IsEnabled = enabled;
|
||||
SaveAdvancedButton.IsEnabled = enabled;
|
||||
}
|
||||
|
||||
private void RefreshProfiles()
|
||||
{
|
||||
ProfilesBox.ItemsSource = _settings.Profiles.Select(profile => profile.DisplayName).ToList();
|
||||
}
|
||||
|
||||
private void LoadProfileButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var index = ProfilesBox.SelectedIndex;
|
||||
if (index < 0 || index >= _settings.Profiles.Count)
|
||||
{
|
||||
UpdateStatus("Bitte zuerst ein Profil auswaehlen.");
|
||||
return;
|
||||
}
|
||||
|
||||
var profile = _settings.Profiles[index];
|
||||
_settings.BaseUrl = NormalizeBaseUrl(profile.BaseUrl) ?? _settings.BaseUrl;
|
||||
_settings.UploadUrl = profile.UploadUrl;
|
||||
_settings.Username = profile.Username;
|
||||
_settings.Password = profile.Password;
|
||||
_settings.ResponseFormat = profile.ResponseFormat;
|
||||
_settings.WatchFolder = profile.WatchFolder;
|
||||
_settings.IncludePatterns = profile.IncludePatterns;
|
||||
_settings.ExcludePatterns = profile.ExcludePatterns;
|
||||
_settings.MaxConcurrentUploads = profile.MaxConcurrentUploads > 0 ? profile.MaxConcurrentUploads : _settings.MaxConcurrentUploads;
|
||||
_settings.UploadDelayMs = profile.UploadDelayMs;
|
||||
_settingsStore.Save(_settings);
|
||||
|
||||
ApplySettings();
|
||||
UpdateStatus("Profil geladen.");
|
||||
}
|
||||
|
||||
private void SaveProfileButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var label = _settings.EventName ?? "Neues Profil";
|
||||
var profile = new PhotoboothProfile
|
||||
{
|
||||
Label = label,
|
||||
EventName = _settings.EventName,
|
||||
BaseUrl = _settings.BaseUrl,
|
||||
UploadUrl = _settings.UploadUrl,
|
||||
Username = _settings.Username,
|
||||
Password = _settings.Password,
|
||||
ResponseFormat = _settings.ResponseFormat,
|
||||
WatchFolder = _settings.WatchFolder,
|
||||
IncludePatterns = _settings.IncludePatterns,
|
||||
ExcludePatterns = _settings.ExcludePatterns,
|
||||
MaxConcurrentUploads = _settings.MaxConcurrentUploads,
|
||||
UploadDelayMs = _settings.UploadDelayMs,
|
||||
};
|
||||
|
||||
_settings.Profiles.RemoveAll(existing => string.Equals(existing.DisplayName, profile.DisplayName, StringComparison.OrdinalIgnoreCase));
|
||||
_settings.Profiles.Insert(0, profile);
|
||||
_settingsStore.Save(_settings);
|
||||
RefreshProfiles();
|
||||
ProfilesBox.SelectedIndex = 0;
|
||||
UpdateStatus("Profil gespeichert.");
|
||||
}
|
||||
|
||||
private async void LogCopyButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var content = ReadLogForCopy();
|
||||
if (string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
UpdateStatus("Log ist leer.");
|
||||
return;
|
||||
}
|
||||
|
||||
var clipboard = TopLevel.GetTopLevel(this)?.Clipboard;
|
||||
if (clipboard is null)
|
||||
{
|
||||
UpdateStatus("Zwischenablage nicht verfuegbar.");
|
||||
return;
|
||||
}
|
||||
|
||||
await clipboard.SetTextAsync(content);
|
||||
UpdateStatus("Log kopiert.");
|
||||
}
|
||||
|
||||
private void AppendLog(string message)
|
||||
{
|
||||
var line = $"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss} {message}";
|
||||
_logBuffer.Add(line);
|
||||
while (_logBuffer.Count > 200)
|
||||
{
|
||||
_logBuffer.RemoveAt(0);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File.AppendAllLines(_settingsStore.LogPath, new[] { line });
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore file errors
|
||||
}
|
||||
}
|
||||
|
||||
private string ReadLogForCopy()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_settingsStore.LogPath))
|
||||
{
|
||||
var lines = File.ReadAllLines(_settingsStore.LogPath);
|
||||
return string.Join(Environment.NewLine, lines.TakeLast(200));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
return _logBuffer.Count > 0 ? string.Join(Environment.NewLine, _logBuffer) : string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace PhotoboothUploader.Models;
|
||||
|
||||
public sealed class PhotoboothProfile
|
||||
{
|
||||
public string? Label { get; set; }
|
||||
public string? EventName { get; set; }
|
||||
public string? BaseUrl { get; set; }
|
||||
public string? UploadUrl { get; set; }
|
||||
public string? Username { get; set; }
|
||||
public string? Password { get; set; }
|
||||
public string? ResponseFormat { get; set; }
|
||||
public string? WatchFolder { get; set; }
|
||||
public string? IncludePatterns { get; set; }
|
||||
public string? ExcludePatterns { get; set; }
|
||||
public int MaxConcurrentUploads { get; set; } = 2;
|
||||
public int UploadDelayMs { get; set; } = 500;
|
||||
|
||||
public string DisplayName
|
||||
=> !string.IsNullOrWhiteSpace(Label)
|
||||
? Label
|
||||
: !string.IsNullOrWhiteSpace(EventName)
|
||||
? EventName
|
||||
: UploadUrl ?? BaseUrl ?? "Profil";
|
||||
}
|
||||
@@ -16,6 +16,10 @@ public sealed class PhotoboothSettings
|
||||
public string? ExcludePatterns { get; set; }
|
||||
public List<string> PendingUploads { get; set; } = new();
|
||||
public Dictionary<string, string> UploadedFiles { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||
public List<PhotoboothProfile> Profiles { get; set; } = new();
|
||||
public string? ConnectExpiresAt { get; set; }
|
||||
public string? LastSeenFile { get; set; }
|
||||
public string? LastSeenAt { get; set; }
|
||||
public string? LastError { get; set; }
|
||||
public string? LastErrorAt { get; set; }
|
||||
public int MaxConcurrentUploads { get; set; } = 2;
|
||||
|
||||
@@ -14,6 +14,7 @@ public sealed class SettingsStore
|
||||
};
|
||||
|
||||
public string SettingsPath { get; }
|
||||
public string LogPath { get; }
|
||||
|
||||
public SettingsStore()
|
||||
{
|
||||
@@ -24,6 +25,7 @@ public sealed class SettingsStore
|
||||
|
||||
Directory.CreateDirectory(basePath);
|
||||
SettingsPath = Path.Combine(basePath, "settings.json");
|
||||
LogPath = Path.Combine(basePath, "uploader.log");
|
||||
}
|
||||
|
||||
public PhotoboothSettings Load()
|
||||
|
||||
Reference in New Issue
Block a user