ln.podget/ln.tagorganizer/MediaFile.cs

153 lines
3.9 KiB
C#

using System.Security.Cryptography;
using ln.type;
using TagLib;
using File = System.IO.File;
namespace ln.tagorganizer;
public class MediaFile : IDisposable
{
public static MediaFile Create(string filename)
{
try
{
TagLib.File tagFile = TagLib.File.Create(filename);
return new MediaFile(filename);
}
catch (UnsupportedFormatException)
{
return null;
}
}
public string FileName { get; private set; }
public string Extension => Path.GetExtension(FileName);
public string BaseName => Path.GetFileNameWithoutExtension(FileName);
public string? DirectoryName => Path.GetDirectoryName(FileName);
public string HashCacheName => GetHashCacheName(FileName);
public MediaFile(string filename) :this(filename, null)
{ }
private MediaFile(string filename, TagLib.File? tagFile)
{
FileName = filename;
if (!File.Exists(FileName))
throw new FileNotFoundException();
_tagFile = tagFile;
if (!LoadTagFile())
throw new UnsupportedFormatException();
}
public TagLib.Tag Tag => _tagFile.Tag;
private TagLib.File _tagFile;
private bool LoadTagFile()
{
if (_tagFile is null)
{
try
{
_tagFile = TagLib.File.Create(FileName);
}
catch (UnsupportedFormatException)
{
return false;
}
}
return true;
}
private void UnloadTagFile()
{
_tagFile?.Dispose();
_tagFile = null;
}
private byte[] _hash;
public byte[] Hash
{
get
{
if (_hash is null)
ComputeFileHash();
return _hash;
}
}
public string HashString => Hash.ToHexString();
public void Move(string newFileName)
{
UnloadTagFile();
File.Move(FileName, newFileName);
if (File.Exists(HashCacheName))
{
try
{
File.Move(HashCacheName, GetHashCacheName(newFileName));
}
catch (Exception e) { }
}
RemoveDirectoryIfEmpty(Path.GetDirectoryName(FileName));
FileName = newFileName;
LoadTagFile();
}
public MediaFile Copy(string newFileName)
{
File.Copy(FileName, newFileName);
if (File.Exists(HashCacheName))
{
try
{
File.Copy(HashCacheName, GetHashCacheName(newFileName));
}
catch (Exception e) { }
}
return new MediaFile(newFileName);
}
private void RemoveDirectoryIfEmpty(string directoryName)
{
if (Directory.GetFileSystemEntries(directoryName).Length == 0)
Directory.Delete(directoryName);
}
private void ComputeFileHash()
{
if (File.Exists(HashCacheName) && (File.GetLastWriteTime(HashCacheName) > File.GetLastWriteTime(FileName)))
{
_hash = File.ReadAllBytes(HashCacheName);
if (_hash.Length == 32)
return;
}
SHA256 sha256 = SHA256.Create();
using (FileStream fs = new FileStream(FileName, FileMode.Open))
_hash = sha256.ComputeHash(fs);
File.WriteAllBytes(HashCacheName, _hash);
}
private static string GetHashCacheName(string filename)
{
string directoryName = Path.GetDirectoryName(filename);
string baseName = Path.GetFileName(filename);
string hashName = Path.Combine(directoryName, ".hash." + baseName);
return hashName;
}
public override bool Equals(object? obj) => (obj is MediaFile other) && other.FileName.Equals(FileName);
public override int GetHashCode() => Hash.GetHashCode();
public void Dispose()
{
_tagFile?.Dispose();
}
}