Files
LlamaCasty/Services/AlertClipCleanup.cs
T
gramps 1a6a549e17 feat(55): stop leaving disk debts — temp clips and a low-disk guard
595 green, 0 warnings. Completes TASK 55 (slice 1, log rotation, shipped 2026-10-22).

- **`AlertClipCleanup`**: the default alert clip is materialised into `%TEMP%` for ffmpeg to read, and
  nothing ever deleted it — one orphan per profile that ever played an alert. Now: delete this session's
  file in `Shutdown`, and sweep `ytLive-alert-*.mp4` at startup for anything a crash left behind. Only
  the prefix we own is touched; a directory is never deleted.
- **`DiskSpaceGuard`**: a recording that dies of a full disk is a trust breach, so the numbers are a
  pure policy — refuse to start under **1 GB** (toast; the stream still starts, recording does not),
  warn under **5 GB** at start ("about eighty minutes" at 8 Mbps ≈ 3.6 GB/h), and one mid-show warning
  under **2 GB** — the last useful moment before the encoder fails for a reason it won't explain.
  Unreadable drives (a USB stick that just left) return null and never block a running recording.

Tests are policy-level on purpose: filling a real drive is not a test. `DiskHygieneTests` proves the
sweep only removes our own files and that the thresholds behave at both ends.
2026-11-10 11:55:42 -08:00

61 lines
1.9 KiB
C#

using System;
using System.IO;
namespace ytLive.Services;
/// <summary>
/// TASK 55·2: the default alert clip is materialised into <c>%TEMP%</c> so ffmpeg can read it as a file.
/// Nothing used to delete it, so every profile that ever played an alert left an orphan behind.
///
/// <para>Two touches, deliberately simple: delete this session's file on close, and sweep anything the
/// prefix matches at startup (a crash leaves the same debris a clean exit does not). Only files this app
/// created are touched — the prefix is the contract, and the sweep never deletes a directory.</para>
/// </summary>
public static class AlertClipCleanup
{
public const string Prefix = "ytLive-alert-";
/// <summary>Deletes stale alert clips left in <paramref name="directory"/>. Returns how many went.
/// Missing directory is not an error.</summary>
public static int Sweep(string directory)
{
try
{
if (!Directory.Exists(directory)) return 0;
var removed = 0;
foreach (var path in Directory.EnumerateFiles(directory, Prefix + "*.mp4"))
{
if (TryDelete(path)) removed++;
}
return removed;
}
catch (Exception ex)
{
Helpers.AppLog.Write(ex, "Alert clip sweep failed");
return 0;
}
}
/// <summary>Deletes one clip if it exists. Safe on null/blank and on a locked file.</summary>
public static bool Delete(string? path)
{
if (string.IsNullOrWhiteSpace(path)) return false;
return TryDelete(path);
}
private static bool TryDelete(string path)
{
try
{
if (!File.Exists(path)) return false;
File.Delete(path);
return true;
}
catch (Exception ex)
{
Helpers.AppLog.Write(ex, $"Alert clip delete failed: {path}");
return false;
}
}
}