57 lines
2.2 KiB
C#
57 lines
2.2 KiB
C#
namespace VideoDownloader.App.Services;
|
|
|
|
/// <summary>
|
|
/// UC-D21 다운로드 예약 — 지정 시간대(예: 야간 02:00~08:00)에만 다운로드를 허용하는 게이트.
|
|
/// 시간 창은 "HH:mm-HH:mm" 형식. 자정을 가로지르는 창(22:00-06:00)도 지원한다.
|
|
/// </summary>
|
|
public sealed class DownloadScheduler
|
|
{
|
|
/// <summary>예약 창("HH:mm-HH:mm"). null/빈이면 항상 허용.</summary>
|
|
public string? Window { get; }
|
|
|
|
/// <summary>예약 창이 설정돼 있으면 true.</summary>
|
|
public bool Enabled => !string.IsNullOrWhiteSpace(Window);
|
|
|
|
public DownloadScheduler(string? window = null)
|
|
{
|
|
Window = string.IsNullOrWhiteSpace(window) ? null : window.Trim();
|
|
}
|
|
|
|
/// <summary>지정 시각에 다운로드가 허용되는지.</summary>
|
|
public bool CanRunNow(DateTime now)
|
|
{
|
|
if (!Enabled || TryParse(Window!, out var start, out var end) == false) return true;
|
|
var t = now.TimeOfDay;
|
|
return start <= end
|
|
? t >= start && t < end
|
|
: t >= start || t < end; // 자정 가로지름(예: 22:00-06:00)
|
|
}
|
|
|
|
/// <summary>다음 예약 창 시작까지 남은 시간. 항상 허용이면 Zero.</summary>
|
|
public TimeSpan TimeUntilNextWindow(DateTime now)
|
|
{
|
|
if (!Enabled || !TryParse(Window!, out var start, out _)) return TimeSpan.Zero;
|
|
var target = now.Date + start;
|
|
if (target <= now) target = target.AddDays(1);
|
|
return target - now;
|
|
}
|
|
|
|
/// <summary>"HH:mm-HH:mm" 파싱. 형식이 틀리면 false(게이트는 열린 채 둔다).</summary>
|
|
public static bool TryParse(string window, out TimeSpan start, out TimeSpan end)
|
|
{
|
|
start = end = TimeSpan.Zero;
|
|
var parts = (window ?? "").Split('-');
|
|
if (parts.Length != 2) return false;
|
|
return TryParseTime(parts[0], out start) && TryParseTime(parts[1], out end);
|
|
}
|
|
|
|
private static bool TryParseTime(string s, out TimeSpan ts)
|
|
{
|
|
ts = TimeSpan.Zero;
|
|
var p = s.Trim().Split(':');
|
|
if (p.Length != 2 || !int.TryParse(p[0], out var h) || !int.TryParse(p[1], out var m)) return false;
|
|
if (h is < 0 or > 23 || m is < 0 or > 59) return false;
|
|
ts = new TimeSpan(h, m, 0);
|
|
return true;
|
|
}
|
|
}
|