refactor(1): move Detection (MediaDetector/SocialSiteDetector/DetectionContext) App->Core
This commit is contained in:
parent
b6b7fc341b
commit
1aab8729fa
6 changed files with 6 additions and 6 deletions
81
VideoDownloader.Core/Detection/MediaDetector.cs
Normal file
81
VideoDownloader.Core/Detection/MediaDetector.cs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
using VideoDownloader.Core.Config;
|
||||
|
||||
namespace VideoDownloader.Core.Detection;
|
||||
|
||||
/// <summary>요청(URL + content-type + 길이)과 설정으로 미디어 종류를 판정.</summary>
|
||||
public static class MediaDetector
|
||||
{
|
||||
/// <returns>HLS 또는 Direct, 감지 대상이 아니면 null</returns>
|
||||
public static MediaKind? Classify(string? uri, string? contentType, long len, AppConfig config)
|
||||
{
|
||||
var l = (uri ?? "").ToLowerInvariant();
|
||||
var c = (contentType ?? "").ToLowerInvariant();
|
||||
|
||||
bool isHls = c.Contains("mpegurl") || l.Contains(".m3u8") || l.Contains(".m3u");
|
||||
if (isHls)
|
||||
return Enabled(config, "hls") ? MediaKind.Hls : null;
|
||||
|
||||
bool isDash = c.Contains("dash+xml") || l.Contains(".mpd");
|
||||
if (isDash)
|
||||
return Enabled(config, "dash") ? MediaKind.Dash : null;
|
||||
|
||||
long min = config.MinSizeMB * 1024L * 1024L;
|
||||
if (len >= 0 && len <= min) return null; // 너무 작음
|
||||
|
||||
var fmt = MatchFormat(l, c);
|
||||
if (fmt == null) return null;
|
||||
return Enabled(config, fmt) ? MediaKind.Direct : null;
|
||||
}
|
||||
|
||||
private static bool Enabled(AppConfig config, string key) => config.EnabledFormats.Contains(key);
|
||||
|
||||
/// <summary>형식 키 반환: mp4/webm/mkv/m4v/mov/avi/audio (미매칭 null)</summary>
|
||||
public static string? MatchFormat(string l, string c)
|
||||
{
|
||||
if (l.EndsWith(".mp4") || c.Contains("mp4")) return "mp4";
|
||||
if (l.EndsWith(".webm") || c.Contains("webm")) return "webm";
|
||||
if (l.EndsWith(".mkv") || c.Contains("matroska")) return "mkv";
|
||||
if (l.EndsWith(".m4v")) return "m4v";
|
||||
if (l.EndsWith(".mov") || c.Contains("quicktime")) return "mov";
|
||||
if (l.EndsWith(".avi") || c.Contains("x-msvideo")) return "avi";
|
||||
bool audio = c.StartsWith("audio/") || l.EndsWith(".m4a") || l.EndsWith(".mp3")
|
||||
|| l.EndsWith(".ogg") || l.EndsWith(".opus") || l.EndsWith(".flac")
|
||||
|| l.EndsWith(".wav") || l.EndsWith(".aac");
|
||||
if (audio) return "audio";
|
||||
if (c.StartsWith("video/")) return "mp4"; // 기타 video 는 mp4 취급
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>감지 후보(사람에게 보여줄 만한) 판정 - DASH/MSE/세그먼트 등</summary>
|
||||
public static bool LooksLikeCandidate(string l, string c) =>
|
||||
l.Contains(".m4s") || l.Contains("segment") || l.Contains("/init") || l.Contains(".ts?")
|
||||
|| l.Contains(".mpd") || c.Contains("dash+xml") || c.Contains("mp2t") || c.Contains("octet-stream");
|
||||
|
||||
/// <summary>#15 본문 선두 magic byte 로 실제 포맷 판별 (위장 image/* 등 검증용).
|
||||
/// 이미지 포맷(GIF/PNG/JPEG/WebP)은 null 반환 — 위장 트래킹 픽셀이 미디어로 오탐되는 것 방지.
|
||||
/// (GIF 'G'=0x47 가 MPEG-TS sync byte 와 겹쳐 ts 로 오탐되던 문제 수정)</summary>
|
||||
public static string? ProbeFormat(ReadOnlySpan<byte> h)
|
||||
{
|
||||
if (h.Length < 4) return null;
|
||||
|
||||
// 이미지 포맷 → 미디어 아님
|
||||
if (h.Length >= 3 && h[0] == 'G' && h[1] == 'I' && h[2] == 'F') return null; // GIF
|
||||
if (h.Length >= 8 && h[0] == 0x89 && h[1] == 0x50 && h[2] == 0x4E && h[3] == 0x47) return null; // PNG
|
||||
if (h.Length >= 3 && h[0] == 0xFF && h[1] == 0xD8 && h[2] == 0xFF) return null; // JPEG
|
||||
if (h.Length >= 12 && h[0] == 0x52 && h[1] == 0x49 && h[2] == 0x46 && h[3] == 0x46) // RIFF
|
||||
{
|
||||
if (h[8] == 'W' && h[9] == 'E' && h[10] == 'B' && h[11] == 'P') return null; // WebP(이미지)
|
||||
if (h[8] == 'W' && h[9] == 'A' && h[10] == 'V' && h[11] == 'E') return "wav"; // WAV(오디오)
|
||||
return null;
|
||||
}
|
||||
|
||||
if (h.Length >= 12 && h[4] == 'f' && h[5] == 't' && h[6] == 'y' && h[7] == 'p') return "mp4"; // ftyp box
|
||||
if (h[0] == 0x47) return "ts"; // MPEG-TS sync (GIF 는 위에서 걸러짐)
|
||||
if (h[0] == 0x1A && h[1] == 0x45 && h[2] == 0xDF && h[3] == 0xA3) return "webm"; // EBML
|
||||
if (h[0] == 'I' && h[1] == 'D' && h[2] == '3') return "mp3"; // ID3
|
||||
if (h[0] == 0xFF && (h[1] & 0xE0) == 0xE0) return "mp3"; // MP3 frame
|
||||
if (h[0] == 0x66 && h[1] == 0x4C && h[2] == 0x61 && h[3] == 0x43) return "flac"; // fLaC
|
||||
if (h[0] == 0x4F && h[1] == 0x67 && h[2] == 0x67 && h[3] == 0x53) return "ogg"; // OggS
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue