172 lines
5.1 KiB
C#
172 lines
5.1 KiB
C#
using System.Globalization;
|
|
using System.Text.Json;
|
|
|
|
namespace EmbyToolbox.Services;
|
|
|
|
/// <summary>
|
|
/// Извлечение количества аудиодорожек и оценка суммарного размера аудио по JSON ffprobe.
|
|
/// </summary>
|
|
public static class FfprobeAudioInfoParser
|
|
{
|
|
public static FfprobeAudioInfo? TryParse(string json)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
using var doc = JsonDocument.Parse(json);
|
|
return ParseRoot(doc.RootElement);
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static FfprobeAudioInfo? ParseRoot(JsonElement root)
|
|
{
|
|
if (root.ValueKind != JsonValueKind.Object)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
double? formatDurationSec = null;
|
|
if (root.TryGetProperty("format", out var format) && format.ValueKind == JsonValueKind.Object)
|
|
{
|
|
formatDurationSec = TryReadDurationSeconds(format);
|
|
}
|
|
|
|
if (!root.TryGetProperty("streams", out var streams) || streams.ValueKind != JsonValueKind.Array)
|
|
{
|
|
return new FfprobeAudioInfo(0, null, false);
|
|
}
|
|
|
|
var audioList = new List<JsonElement>();
|
|
foreach (var stream in streams.EnumerateArray())
|
|
{
|
|
if (stream.ValueKind == JsonValueKind.Object &&
|
|
stream.TryGetProperty("codec_type", out var ct) &&
|
|
ct.ValueKind == JsonValueKind.String &&
|
|
string.Equals(ct.GetString(), "audio", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
audioList.Add(stream);
|
|
}
|
|
}
|
|
|
|
var count = audioList.Count;
|
|
if (count == 0)
|
|
{
|
|
return new FfprobeAudioInfo(0, 0, false);
|
|
}
|
|
|
|
var partial = false;
|
|
var totalBytes = 0.0;
|
|
var anySize = false;
|
|
|
|
foreach (var stream in audioList)
|
|
{
|
|
var duration = TryReadStreamDurationSeconds(stream) ?? formatDurationSec;
|
|
var bps = TryReadBitrateBps(stream);
|
|
if (duration is null || bps is null)
|
|
{
|
|
partial = true;
|
|
continue;
|
|
}
|
|
|
|
if (double.IsNaN(duration.Value) || double.IsInfinity(duration.Value) || duration.Value <= 0)
|
|
{
|
|
partial = true;
|
|
continue;
|
|
}
|
|
|
|
if (bps.Value <= 0)
|
|
{
|
|
partial = true;
|
|
continue;
|
|
}
|
|
|
|
totalBytes += duration.Value * (bps.Value / 8.0);
|
|
anySize = true;
|
|
}
|
|
|
|
int? sizeMb;
|
|
if (!anySize)
|
|
{
|
|
sizeMb = null;
|
|
}
|
|
else
|
|
{
|
|
var mb = totalBytes / (1024.0 * 1024.0);
|
|
sizeMb = (int)Math.Round(mb, MidpointRounding.AwayFromZero);
|
|
}
|
|
|
|
return new FfprobeAudioInfo(count, sizeMb, partial);
|
|
}
|
|
|
|
private static double? TryReadDurationSeconds(JsonElement el)
|
|
{
|
|
if (el.TryGetProperty("duration", out var d) && d.ValueKind == JsonValueKind.String)
|
|
{
|
|
if (double.TryParse(d.GetString(), NumberStyles.Any, CultureInfo.InvariantCulture, out var s))
|
|
{
|
|
return s;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static double? TryReadStreamDurationSeconds(JsonElement stream)
|
|
{
|
|
return TryReadDurationSeconds(stream);
|
|
}
|
|
|
|
private static long? TryReadBitrateBps(JsonElement stream)
|
|
{
|
|
if (stream.TryGetProperty("bit_rate", out var br) && br.ValueKind == JsonValueKind.String)
|
|
{
|
|
var s = br.GetString();
|
|
if (long.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var b) && b > 0)
|
|
{
|
|
return b;
|
|
}
|
|
}
|
|
|
|
if (stream.TryGetProperty("max_bit_rate", out var mbr) && mbr.ValueKind == JsonValueKind.String)
|
|
{
|
|
var s = mbr.GetString();
|
|
if (long.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var b) && b > 0)
|
|
{
|
|
return b;
|
|
}
|
|
}
|
|
|
|
if (stream.TryGetProperty("tags", out var tags) && tags.ValueKind == JsonValueKind.Object)
|
|
{
|
|
foreach (var p in tags.EnumerateObject())
|
|
{
|
|
if (p.Name.Contains("BPS", StringComparison.OrdinalIgnoreCase) &&
|
|
p.Value.ValueKind is JsonValueKind.String or JsonValueKind.Number)
|
|
{
|
|
if (p.Value.ValueKind == JsonValueKind.String && long.TryParse(p.Value.GetString(), NumberStyles.Any, CultureInfo.InvariantCulture, out var b) && b > 0)
|
|
{
|
|
return b;
|
|
}
|
|
|
|
if (p.Value.ValueKind == JsonValueKind.Number && p.Value.TryGetInt64(out var n) && n > 0)
|
|
{
|
|
return n;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public readonly record struct FfprobeAudioInfo(int AudioStreamCount, int? AudioSizeMbTotal, bool IsPartial);
|