153 lines
3.9 KiB
C#
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();
|
|
}
|
|
} |