Update README.md with project details, features, requirements, architecture, and data management for PLib video library manager.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
namespace PLib.Domain.Videos;
|
||||
|
||||
/// <summary>
|
||||
/// A single video file that belongs to the library.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The absolute path is the natural identity of a video: the library is a view over the
|
||||
/// file system, so two entries pointing at the same path are the same video. Mutation goes
|
||||
/// through explicit methods so that the entity can never end up half-updated.
|
||||
/// </remarks>
|
||||
public sealed class VideoItem
|
||||
{
|
||||
/// <summary>Required by EF Core materialization; do not use from application code.</summary>
|
||||
private VideoItem()
|
||||
{
|
||||
FullPath = null!;
|
||||
Title = null!;
|
||||
}
|
||||
|
||||
public VideoItem(string fullPath, string title, long sizeInBytes, DateTimeOffset fileModifiedAt)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(fullPath);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(title);
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(sizeInBytes);
|
||||
|
||||
Id = Guid.CreateVersion7();
|
||||
FullPath = fullPath;
|
||||
Title = title;
|
||||
SizeInBytes = sizeInBytes;
|
||||
FileModifiedAt = fileModifiedAt;
|
||||
AddedAt = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public Guid Id { get; private set; }
|
||||
|
||||
/// <summary>Absolute path of the file on disk. Unique within the library.</summary>
|
||||
public string FullPath { get; private set; }
|
||||
|
||||
/// <summary>Human readable name; defaults to the file name without extension.</summary>
|
||||
public string Title { get; private set; }
|
||||
|
||||
public long SizeInBytes { get; private set; }
|
||||
|
||||
public TimeSpan? Duration { get; private set; }
|
||||
|
||||
public int? Width { get; private set; }
|
||||
|
||||
public int? Height { get; private set; }
|
||||
|
||||
public string? VideoCodec { get; private set; }
|
||||
|
||||
/// <summary>Absolute path of the generated poster frame, or <c>null</c> if none exists yet.</summary>
|
||||
public string? ThumbnailPath { get; private set; }
|
||||
|
||||
/// <summary>Last write time of the file when it was last indexed.</summary>
|
||||
public DateTimeOffset FileModifiedAt { get; private set; }
|
||||
|
||||
public DateTimeOffset AddedAt { get; private set; }
|
||||
|
||||
/// <summary>True once the file has been probed and a poster frame produced.</summary>
|
||||
public bool IsIndexed => Duration is not null && ThumbnailPath is not null;
|
||||
|
||||
public void Rename(string title)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(title);
|
||||
Title = title;
|
||||
}
|
||||
|
||||
public void ApplyTechnicalInfo(VideoTechnicalInfo info)
|
||||
{
|
||||
Duration = info.Duration;
|
||||
Width = info.Width;
|
||||
Height = info.Height;
|
||||
VideoCodec = info.VideoCodec;
|
||||
}
|
||||
|
||||
public void AttachThumbnail(string thumbnailPath)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(thumbnailPath);
|
||||
ThumbnailPath = thumbnailPath;
|
||||
}
|
||||
|
||||
public void DetachThumbnail() => ThumbnailPath = null;
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the file system facts after the file changed on disk, and invalidates
|
||||
/// everything that was derived from the previous revision of the file.
|
||||
/// </summary>
|
||||
public void RefreshFileFacts(long sizeInBytes, DateTimeOffset fileModifiedAt)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(sizeInBytes);
|
||||
|
||||
if (SizeInBytes == sizeInBytes && FileModifiedAt == fileModifiedAt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SizeInBytes = sizeInBytes;
|
||||
FileModifiedAt = fileModifiedAt;
|
||||
ApplyTechnicalInfo(VideoTechnicalInfo.Unknown);
|
||||
DetachThumbnail();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user