Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* (at your option) any later version.
*/

using System.Globalization;
using System.Text.Json;
using Microsoft.Extensions.Logging;

Expand Down Expand Up @@ -65,16 +66,20 @@ internal static class MyAnonamousePublishDateParser
double? hours = null;
double? minutes = null;

// These three ages are machine format like every other number in this
// indexer's JSON, so they are pinned for uniformity. No damage was
// measured here: the values seen in practice are whole numbers, which
// read the same under every culture.
// Prefer explicit ageHours/ageMinutes if present
if (item.TryGetProperty("ageHours", out var ah) && (ah.ValueKind == JsonValueKind.Number || ah.ValueKind == JsonValueKind.String))
{
if (ah.ValueKind == JsonValueKind.Number) hours = ah.GetDouble();
else if (double.TryParse(ah.GetString(), out var htmp)) hours = htmp;
else if (double.TryParse(ah.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture, out var htmp)) hours = htmp;
}
if (item.TryGetProperty("ageMinutes", out var am) && (am.ValueKind == JsonValueKind.Number || am.ValueKind == JsonValueKind.String))
{
if (am.ValueKind == JsonValueKind.Number) minutes = am.GetDouble();
else if (double.TryParse(am.GetString(), out var mtmp)) minutes = mtmp;
else if (double.TryParse(am.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture, out var mtmp)) minutes = mtmp;
}

// Fallback to 'age' if present. Heuristic: small values (<=48) likely hours; otherwise treat as days.
Expand All @@ -86,7 +91,8 @@ internal static class MyAnonamousePublishDateParser
if (a <= 48) hours = a;
else days = (int)Math.Floor(a);
}
else if (ageElem.ValueKind == JsonValueKind.String && double.TryParse(ageElem.GetString(), out var adtmp))
else if (ageElem.ValueKind == JsonValueKind.String
&& double.TryParse(ageElem.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture, out var adtmp))
{
var a = adtmp;
if (a <= 48) hours = a;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static long ExtractFromDescription(string? description, ILogger logger)

var sizeValue = match.Groups[1].Value.Replace(",", "");
var unit = match.Groups[2].Value.ToUpper();
if (double.TryParse(sizeValue, out var value))
if (double.TryParse(sizeValue, NumberStyles.Float, CultureInfo.InvariantCulture, out var value))
{
var result = ParseDecimalUnit(value, unit, binary: true);
logger.LogDebug("Extracted size from MyAnonamouse description formatted: {Value} {Unit} = {Result} bytes", value, unit, result);
Expand All @@ -46,7 +46,7 @@ public static long ExtractFromDescription(string? description, ILogger logger)
{
var sizeValue = match.Groups[1].Value.Replace(",", "");
var unit = match.Groups[2].Value.ToUpper();
if (double.TryParse(sizeValue, out var value))
if (double.TryParse(sizeValue, NumberStyles.Float, CultureInfo.InvariantCulture, out var value))
{
var result = ParseDecimalUnit(value, unit, binary: true);
logger.LogDebug("Extracted size from MyAnonamouse description (no bytes): {Value} {Unit} = {Result} bytes", value, unit, result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ namespace Listenarr.Application.Search.Indexers.Torznab
{
internal sealed partial class TorznabResponseParser
{
private long ParseSizeString(string sizeStr)
/// <summary>
/// Reads a size out of a Torznab attribute value, either as plain bytes or as a
/// formatted string such as "1.5 GiB".
/// </summary>
/// <remarks>
/// Internal rather than private so the culture behaviour of the unit match can be
/// asserted against the real method rather than a copy of it.
/// </remarks>
internal long ParseSizeString(string sizeStr)
{
if (string.IsNullOrEmpty(sizeStr))
return 0;
Expand All @@ -26,7 +34,10 @@ private long ParseSizeString(string sizeStr)
if (match.Success &&
double.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var value))
{
var unit = match.Groups[2].Value.ToUpper();
// ToUpperInvariant, not ToUpper: under tr-TR the 'i' of "GiB" uppercases to
// 'I' with a dot (U+0130), no binary arm matches, and the size falls through
// to the (long)value default, which is the raw mantissa in bytes.
var unit = match.Groups[2].Value.ToUpperInvariant();
return unit switch
{
"B" => (long)value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ public static double ParseSpeed(string speedStr)
var parts = speedStr.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 0) return 0;

if (!double.TryParse(parts[0], out var value)) return 0;
// NumberStyles.Float rather than Any: Any carries AllowThousands, AllowCurrencySymbol
// and AllowParentheses, so under the invariant culture "1,5" reads as 15 and "(1.5)"
// as -1.5. SABnzbd emits a plain decimal, and a value that is not one should fail.
if (!double.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var value)) return 0;

if (parts.Length > 1)
{
Expand Down Expand Up @@ -317,7 +320,9 @@ private static double GetDouble(JsonElement element, string propertyName)
if (property.ValueKind == JsonValueKind.Number)
return property.GetDouble();

if (property.ValueKind == JsonValueKind.String && double.TryParse(property.GetString() ?? "0", out var value))
// Float rather than Any, for the reason given on ParseSpeed above.
if (property.ValueKind == JsonValueKind.String
&& double.TryParse(property.GetString() ?? "0", NumberStyles.Float, CultureInfo.InvariantCulture, out var value))
return value;

return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
using System.Globalization;
using System.Text.Json;

namespace Listenarr.Infrastructure.Ffmpeg.Metadata
Expand Down Expand Up @@ -47,7 +48,7 @@ private static void ApplyFormat(AudioMetadata metadata, JsonElement fmt, string
{
if (fmt.TryGetProperty("duration", out var durEl)
&& durEl.ValueKind == JsonValueKind.String
&& double.TryParse(durEl.GetString(), out var dur))
&& double.TryParse(durEl.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture, out var dur))
{
metadata.Duration = TimeSpan.FromSeconds(dur);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

using System.Globalization;
using System.Text.RegularExpressions;

namespace Listenarr.Infrastructure.Search.Providers.Torznab;
Expand All @@ -37,10 +38,12 @@ public static long ParseSize(string sizeStr)
if (!match.Success)
return 0;

if (!double.TryParse(match.Groups[1].Value, out var size))
if (!double.TryParse(match.Groups[1].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var size))
return 0;

var unit = match.Groups[2].Value.ToUpper();
// ToUpperInvariant, not ToUpper: under tr-TR the 'i' of "GiB" uppercases to 'I' with a
// dot (U+0130), no binary arm matches, and the release is recorded as zero bytes.
var unit = match.Groups[2].Value.ToUpperInvariant();
return unit switch
{
"TIB" => (long)(size * 1024 * 1024 * 1024 * 1024),
Expand Down
Loading