forked from sim0n00ps/OF-DL
225 lines
9.5 KiB
C#
225 lines
9.5 KiB
C#
using System.Reflection;
|
|
using HtmlAgilityPack;
|
|
|
|
namespace OF_DL.Services;
|
|
|
|
public class FileNameService(IAuthService authService) : IFileNameService
|
|
{
|
|
/// <summary>
|
|
/// Builds a map of filename token values from post, media, and author data.
|
|
/// </summary>
|
|
/// <param name="info">The post or message object.</param>
|
|
/// <param name="media">The media object.</param>
|
|
/// <param name="author">The author object.</param>
|
|
/// <param name="selectedProperties">The tokens requested by the filename format.</param>
|
|
/// <param name="username">The resolved username when available.</param>
|
|
/// <param name="users">Optional lookup of user IDs to usernames.</param>
|
|
/// <returns>A dictionary of token values keyed by token name.</returns>
|
|
public async Task<Dictionary<string, string>> GetFilename(object info, object media, object author,
|
|
List<string> selectedProperties, string username, Dictionary<string, long>? users = null)
|
|
{
|
|
Dictionary<string, string> values = new();
|
|
Type type1 = info.GetType();
|
|
Type type2 = media.GetType();
|
|
PropertyInfo[] properties1 = type1.GetProperties();
|
|
PropertyInfo[] properties2 = type2.GetProperties();
|
|
|
|
foreach (string propertyName in selectedProperties)
|
|
{
|
|
if (propertyName.Contains("media"))
|
|
{
|
|
object? drmProperty = null;
|
|
object? fileProperty = GetNestedPropertyValue(media, "Files");
|
|
if (fileProperty != null)
|
|
{
|
|
drmProperty = GetNestedPropertyValue(media, "Files.Drm");
|
|
}
|
|
|
|
if (fileProperty != null && drmProperty != null && propertyName == "mediaCreatedAt")
|
|
{
|
|
string? mpdUrl = GetNestedPropertyValue(media, "Files.Drm.Manifest.Dash") as string;
|
|
string? policy =
|
|
GetNestedPropertyValue(media, "Files.Drm.Signature.Dash.CloudFrontPolicy") as string;
|
|
string? signature =
|
|
GetNestedPropertyValue(media, "Files.Drm.Signature.Dash.CloudFrontSignature") as string;
|
|
string? kvp =
|
|
GetNestedPropertyValue(media, "Files.Drm.Signature.Dash.CloudFrontKeyPairId") as string;
|
|
|
|
if (string.IsNullOrEmpty(mpdUrl) || string.IsNullOrEmpty(policy) ||
|
|
string.IsNullOrEmpty(signature) || string.IsNullOrEmpty(kvp) ||
|
|
authService.CurrentAuth == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
DateTime lastModified =
|
|
await DownloadService.GetDrmVideoLastModified(string.Join(",", mpdUrl, policy, signature, kvp),
|
|
authService.CurrentAuth);
|
|
values.Add(propertyName, lastModified.ToString("yyyy-MM-dd"));
|
|
continue;
|
|
}
|
|
|
|
if ((fileProperty == null || drmProperty == null) && propertyName == "mediaCreatedAt")
|
|
{
|
|
object? source = GetNestedPropertyValue(media, "Files.Full.Url");
|
|
if (source != null)
|
|
{
|
|
DateTime lastModified = await DownloadService.GetMediaLastModified(source.ToString() ?? "");
|
|
values.Add(propertyName, lastModified.ToString("yyyy-MM-dd"));
|
|
continue;
|
|
}
|
|
|
|
object? preview = GetNestedPropertyValue(media, "Preview");
|
|
if (preview != null)
|
|
{
|
|
DateTime lastModified = await DownloadService.GetMediaLastModified(preview.ToString() ?? "");
|
|
values.Add(propertyName, lastModified.ToString("yyyy-MM-dd"));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
PropertyInfo? property = Array.Find(properties2,
|
|
p => p.Name.Equals(propertyName.Replace("media", ""), StringComparison.OrdinalIgnoreCase));
|
|
if (property != null)
|
|
{
|
|
object? propertyValue = property.GetValue(media);
|
|
if (propertyValue != null)
|
|
{
|
|
if (propertyValue is DateTime dateTimeValue)
|
|
{
|
|
values.Add(propertyName, dateTimeValue.ToString("yyyy-MM-dd"));
|
|
}
|
|
else
|
|
{
|
|
values.Add(propertyName, propertyValue.ToString() ?? "");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (propertyName.Contains("filename"))
|
|
{
|
|
object? sourcePropertyValue = GetNestedPropertyValue(media, "Files.Full.Url");
|
|
if (sourcePropertyValue != null)
|
|
{
|
|
Uri uri = new(sourcePropertyValue.ToString() ?? "");
|
|
string filename = Path.GetFileName(uri.LocalPath);
|
|
values.Add(propertyName, filename.Split(".")[0]);
|
|
}
|
|
else
|
|
{
|
|
object? nestedPropertyValue = GetNestedPropertyValue(media, "Files.Drm.Manifest.Dash");
|
|
if (nestedPropertyValue != null)
|
|
{
|
|
Uri uri = new(nestedPropertyValue.ToString() ?? "");
|
|
string filename = Path.GetFileName(uri.LocalPath);
|
|
values.Add(propertyName, filename.Split(".")[0] + "_source");
|
|
}
|
|
}
|
|
}
|
|
else if (propertyName.Contains("username"))
|
|
{
|
|
if (!string.IsNullOrEmpty(username))
|
|
{
|
|
values.Add(propertyName, username);
|
|
}
|
|
else
|
|
{
|
|
object? nestedPropertyValue = GetNestedPropertyValue(author, "Id");
|
|
if (nestedPropertyValue != null && users != null)
|
|
{
|
|
values.Add(propertyName,
|
|
users.FirstOrDefault(u => u.Value == Convert.ToInt32(nestedPropertyValue.ToString())).Key);
|
|
}
|
|
}
|
|
}
|
|
else if (propertyName.Contains("text", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
PropertyInfo? property = Array.Find(properties1,
|
|
p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase));
|
|
if (property != null)
|
|
{
|
|
object? propertyValue = property.GetValue(info);
|
|
if (propertyValue != null)
|
|
{
|
|
HtmlDocument pageDoc = new();
|
|
pageDoc.LoadHtml(propertyValue.ToString() ?? "");
|
|
string str = pageDoc.DocumentNode.InnerText;
|
|
if (str.Length > 100) // TODO: add length limit to config
|
|
{
|
|
str = str[..100];
|
|
}
|
|
|
|
values.Add(propertyName, str);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PropertyInfo? property = Array.Find(properties1,
|
|
p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase));
|
|
if (property != null)
|
|
{
|
|
object? propertyValue = property.GetValue(info);
|
|
if (propertyValue != null)
|
|
{
|
|
if (propertyValue is DateTime dateTimeValue)
|
|
{
|
|
values.Add(propertyName, dateTimeValue.ToString("yyyy-MM-dd"));
|
|
}
|
|
else
|
|
{
|
|
values.Add(propertyName, propertyValue.ToString() ?? "");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return values;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies token values to a filename format and removes invalid file name characters.
|
|
/// </summary>
|
|
/// <param name="fileFormat">The filename format string.</param>
|
|
/// <param name="values">Token values to substitute.</param>
|
|
/// <returns>The resolved filename.</returns>
|
|
public Task<string> BuildFilename(string fileFormat, Dictionary<string, string> values)
|
|
{
|
|
foreach (KeyValuePair<string, string> kvp in values)
|
|
{
|
|
string placeholder = "{" + kvp.Key + "}";
|
|
fileFormat = fileFormat.Replace(placeholder, kvp.Value);
|
|
}
|
|
|
|
return Task.FromResult(RemoveInvalidFileNameChars($"{fileFormat}"));
|
|
}
|
|
|
|
private static object? GetNestedPropertyValue(object source, string propertyPath)
|
|
{
|
|
object? value = source;
|
|
foreach (string propertyName in propertyPath.Split('.'))
|
|
{
|
|
if (value == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
PropertyInfo? property = value.GetType().GetProperty(propertyName,
|
|
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
|
if (property == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
value = property.GetValue(value);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
private static string RemoveInvalidFileNameChars(string fileName) => string.IsNullOrEmpty(fileName)
|
|
? fileName
|
|
: string.Concat(fileName.Split(Path.GetInvalidFileNameChars()));
|
|
}
|