Починка импорта, плеер для аудио
This commit is contained in:
@@ -95,20 +95,10 @@ internal sealed class GetSharedMediaQueryHandler : IQueryHandler<GetSharedMediaQ
|
||||
(mType == "image" && (filename.EndsWith(".mp4") || filename.EndsWith(".gif") || url.EndsWith(".gif") || filename.Contains("gif"))) ||
|
||||
(mType == "video" && (filename.Contains("animation") || filename.Contains("gif")));
|
||||
|
||||
if (filterType == "gifs")
|
||||
{
|
||||
return isGif;
|
||||
}
|
||||
|
||||
if (filterType == "files")
|
||||
{
|
||||
return mType != "image" && mType != "video" && mType != "link" && !isGif;
|
||||
}
|
||||
|
||||
if (filterType == "media")
|
||||
{
|
||||
return (mType == "image" || mType == "video") && !isGif;
|
||||
}
|
||||
if (filterType == "gifs") return isGif;
|
||||
if (filterType == "media") return (mType == "image" || mType == "video") && !isGif;
|
||||
if (filterType == "files") return mType == "file" || (mType != "image" && mType != "video" && mType != "link" && !isGif);
|
||||
if (filterType == "links") return mType == "link";
|
||||
|
||||
return true;
|
||||
}).ToList();
|
||||
|
||||
@@ -15,5 +15,5 @@ public record TelegramMessage(
|
||||
long OrderIndex = 0
|
||||
);
|
||||
|
||||
public record TelegramMedia(string FilePath, string FileName, string MimeType);
|
||||
public record TelegramMedia(string FilePath, string FileName, string MimeType, string? Duration = null);
|
||||
public record TelegramReaction(string Emoji, List<string> UserNames);
|
||||
|
||||
@@ -175,7 +175,7 @@ public class TelegramImportWorker : BackgroundService
|
||||
else if (mediaItem.MimeType.Contains("voice") || mediaItem.MimeType.Contains("audio")) itemType = "audio";
|
||||
|
||||
var fileId = await fileStorage.UploadFileAsync(mediaStream, mediaItem.FileName, mimeToUpload);
|
||||
mediaMsg.AddMedia(itemType, $"/api/files/{fileId}", mediaItem.FileName, zipEntry.Length);
|
||||
mediaMsg.AddMedia(itemType, $"/api/files/{fileId}", mediaItem.FileName, zipEntry.Length, mediaItem.Duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -186,16 +186,82 @@ public sealed class TelegramHtmlParser : ITelegramHtmlParser
|
||||
var fullPath = BuildPath(baseDir, href);
|
||||
if (mediaList.Any(m => m.FilePath == fullPath)) continue;
|
||||
|
||||
var fileName = Path.GetFileName(href);
|
||||
// Priority 1: Extract real filename from .title or .name or .description or specific body part
|
||||
string fileName = "";
|
||||
var titleNode = link.QuerySelector(".title") ?? link.QuerySelector(".name") ?? link.QuerySelector(".description");
|
||||
|
||||
if (titleNode != null)
|
||||
{
|
||||
fileName = titleNode.TextContent.Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try body but exclude status
|
||||
var bodyNode = link.QuerySelector(".body");
|
||||
if (bodyNode != null)
|
||||
{
|
||||
var clone = (IElement)bodyNode.Clone();
|
||||
foreach (var s in clone.QuerySelectorAll(".status, .details, .pull_right")) s.Remove();
|
||||
fileName = clone.TextContent.Trim();
|
||||
}
|
||||
|
||||
// Final desperate attempt: link's own content excluding status tags
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
var clone = (IElement)link.Clone();
|
||||
foreach (var s in clone.QuerySelectorAll(".status, .details, .pull_right, .details_icon")) s.Remove();
|
||||
fileName = clone.TextContent.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup & Russian Support
|
||||
if (!string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
// Decrypt potential HTML entities
|
||||
fileName = System.Net.WebUtility.HtmlDecode(fileName);
|
||||
|
||||
// Remove extra lines if any
|
||||
var lines = fileName.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
fileName = lines.Length > 0 ? lines[0].Trim() : "";
|
||||
|
||||
// If the "name" is just "Animation" or generic, we might want to fallback to path
|
||||
if (fileName.Equals("Animation", StringComparison.OrdinalIgnoreCase)) fileName = "";
|
||||
}
|
||||
|
||||
// Priority 2: Fallback to Path filename (e.g. file_1.mp3)
|
||||
if (string.IsNullOrWhiteSpace(fileName) || fileName.Length < 2)
|
||||
{
|
||||
var rawName = Path.GetFileName(href);
|
||||
fileName = System.Net.WebUtility.UrlDecode(rawName);
|
||||
}
|
||||
|
||||
var mimeType = GetMimeType(href);
|
||||
|
||||
bool hasGifClass = link.ClassList.Contains("animated_wrap") || link.ClassList.Contains("media_video");
|
||||
bool hasAnimationText = link.TextContent.Contains("Animation", StringComparison.OrdinalIgnoreCase);
|
||||
bool isVoice = link.ClassList.Contains("media_voice_message") || href.Contains("voice_messages");
|
||||
bool isAudio = link.ClassList.Contains("media_audio_file") || (mimeType.StartsWith("audio") && !isVoice);
|
||||
bool isVideo = link.ClassList.Contains("media_video") || mimeType.StartsWith("video");
|
||||
bool isGif = link.ClassList.Contains("animated_wrap") || link.TextContent.Contains("Animation", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (hasGifClass || hasAnimationText) mimeType = "image/gif";
|
||||
if (link.ClassList.Contains("media_voice_message") || href.Contains("voice_messages")) mimeType = "audio/ogg";
|
||||
if (isGif) mimeType = "image/gif";
|
||||
else if (isVoice) mimeType = "audio/ogg";
|
||||
else if (isAudio && mimeType == "application/octet-stream") mimeType = "audio/mpeg";
|
||||
|
||||
mediaList.Add(new TelegramMedia(fullPath, fileName, mimeType));
|
||||
// Extract Duration from .status
|
||||
string? duration = null;
|
||||
var statusNode = link.QuerySelector(".status") ?? link.QuerySelector(".details");
|
||||
if (statusNode != null)
|
||||
{
|
||||
var text = statusNode.TextContent.Trim();
|
||||
// Status is often: "01:23, 1.2 MB" or just "01:23"
|
||||
var parts = text.Split(',');
|
||||
var first = parts[0].Trim();
|
||||
if (first.Contains(":") && first.All(c => char.IsDigit(c) || c == ':'))
|
||||
{
|
||||
duration = first;
|
||||
}
|
||||
}
|
||||
|
||||
mediaList.Add(new TelegramMedia(fullPath, fileName, mimeType, duration));
|
||||
}
|
||||
|
||||
foreach (var audioEl in node.QuerySelectorAll("audio[src]"))
|
||||
@@ -204,7 +270,7 @@ public sealed class TelegramHtmlParser : ITelegramHtmlParser
|
||||
if (href == null) continue;
|
||||
var fullPath = BuildPath(baseDir, href);
|
||||
if (!mediaList.Any(m => m.FilePath == fullPath))
|
||||
mediaList.Add(new TelegramMedia(fullPath, Path.GetFileName(href), "audio/ogg"));
|
||||
mediaList.Add(new TelegramMedia(fullPath, System.Net.WebUtility.UrlDecode(Path.GetFileName(href)), "audio/ogg"));
|
||||
}
|
||||
|
||||
return mediaList;
|
||||
@@ -244,6 +310,11 @@ public sealed class TelegramHtmlParser : ITelegramHtmlParser
|
||||
".mp4" => "video/mp4",
|
||||
".mov" => "video/quicktime",
|
||||
".webm" => "video/webm",
|
||||
".mp3" => "audio/mpeg",
|
||||
".ogg" => "audio/ogg",
|
||||
".wav" => "audio/wav",
|
||||
".m4a" => "audio/mp4",
|
||||
".aac" => "audio/aac",
|
||||
_ => "application/octet-stream"
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user