Skip to content

Commit f5e71af

Browse files
committed
Handle the case where the date/year field has multiple values [#265]
1 parent 1d5c4b5 commit f5e71af

File tree

2 files changed

+48
-20
lines changed

2 files changed

+48
-20
lines changed

ATL/Entities/MetadataHolder.cs

+44-16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Globalization;
6+
using System.Linq;
67
using System.Text;
78
using static ATL.TagData;
89

@@ -84,7 +85,7 @@ public ushort TrackNumber
8485
{
8586
if (tagData[Field.TRACK_NUMBER_TOTAL] != null)
8687
return TrackUtils.ExtractTrackNumber(tagData[Field.TRACK_NUMBER_TOTAL]);
87-
else return TrackUtils.ExtractTrackNumber(tagData[Field.TRACK_NUMBER]);
88+
return TrackUtils.ExtractTrackNumber(tagData[Field.TRACK_NUMBER]);
8889
}
8990
set => tagData.IntegrateValue(Field.TRACK_NUMBER, value.ToString());
9091
}
@@ -95,9 +96,9 @@ public ushort TrackTotal
9596
{
9697
if (tagData[Field.TRACK_NUMBER_TOTAL] != null)
9798
return TrackUtils.ExtractTrackTotal(tagData[Field.TRACK_NUMBER_TOTAL]);
98-
else if (Utils.IsNumeric(tagData[Field.TRACK_TOTAL]))
99+
if (Utils.IsNumeric(tagData[Field.TRACK_TOTAL]))
99100
return ushort.Parse(tagData[Field.TRACK_TOTAL]);
100-
else return TrackUtils.ExtractTrackTotal(tagData[Field.TRACK_NUMBER]);
101+
return TrackUtils.ExtractTrackTotal(tagData[Field.TRACK_NUMBER]);
101102
}
102103
set => tagData.IntegrateValue(Field.TRACK_TOTAL, value.ToString());
103104
}
@@ -108,7 +109,7 @@ public ushort DiscNumber
108109
{
109110
if (tagData[Field.DISC_NUMBER_TOTAL] != null)
110111
return TrackUtils.ExtractTrackNumber(tagData[Field.DISC_NUMBER_TOTAL]);
111-
else return TrackUtils.ExtractTrackNumber(tagData[Field.DISC_NUMBER]);
112+
return TrackUtils.ExtractTrackNumber(tagData[Field.DISC_NUMBER]);
112113
}
113114
set => tagData.IntegrateValue(Field.DISC_NUMBER, value.ToString());
114115
}
@@ -119,9 +120,9 @@ public ushort DiscTotal
119120
{
120121
if (tagData[Field.DISC_NUMBER_TOTAL] != null)
121122
return TrackUtils.ExtractTrackTotal(tagData[Field.DISC_NUMBER_TOTAL]);
122-
else if (Utils.IsNumeric(tagData[Field.DISC_TOTAL]))
123+
if (Utils.IsNumeric(tagData[Field.DISC_TOTAL]))
123124
return ushort.Parse(tagData[Field.DISC_TOTAL]);
124-
else return TrackUtils.ExtractTrackTotal(tagData[Field.DISC_NUMBER]);
125+
return TrackUtils.ExtractTrackTotal(tagData[Field.DISC_NUMBER]);
125126
}
126127
set => tagData.IntegrateValue(Field.DISC_TOTAL, value.ToString());
127128
}
@@ -130,11 +131,30 @@ public DateTime Date
130131
{
131132
get
132133
{
133-
DateTime result;
134-
if (!DateTime.TryParse(Utils.ProtectValue(tagData[Field.RECORDING_DATE]), out result)) // First try with a proper Recording date field
134+
DateTime result = DateTime.MinValue;
135+
bool success = false;
136+
137+
// The field may be holding multiple values => split it and order it by size desc
138+
string[] dateValues = Array.Empty<string>();
139+
if (tagData.hasKey(Field.RECORDING_DATE))
135140
{
136-
bool success = false;
137-
string dayMonth = Utils.ProtectValue(tagData[Field.RECORDING_DAYMONTH]); // If not, try to assemble year and dateMonth (e.g. ID3v2)
141+
dateValues = tagData[Field.RECORDING_DATE]
142+
.Split(Settings.InternalValueSeparator)
143+
.OrderByDescending(s => s.Length)
144+
.ToArray();
145+
146+
// First try with a proper Recording date field
147+
foreach (var dateValue in dateValues)
148+
{
149+
success = DateTime.TryParse(Utils.ProtectValue(dateValue), out result);
150+
if (success) break;
151+
}
152+
}
153+
154+
// If not, try to assemble year and dateMonth (e.g. ID3v2)
155+
if (!success)
156+
{
157+
string dayMonth = Utils.ProtectValue(tagData[Field.RECORDING_DAYMONTH]);
138158
string year = Utils.ProtectValue(tagData[Field.RECORDING_YEAR]);
139159
if (4 == dayMonth.Length && 4 == year.Length)
140160
{
@@ -152,10 +172,19 @@ public DateTime Date
152172
}
153173
success = DateTime.TryParse(dateTimeBuilder.ToString(), out result);
154174
}
155-
if (!success) // Year only
175+
176+
// Year only
177+
if (!success)
156178
{
157-
if (year.Length != 4) year = Utils.ProtectValue(tagData[Field.RECORDING_DATE]); // ...then with RecordingDate
158-
if (4 == year.Length) // We have a year !
179+
// ...then try with RecordingDate
180+
foreach (var dateValue in dateValues)
181+
{
182+
if (4 == year.Length) break;
183+
year = Utils.ProtectValue(dateValue);
184+
}
185+
186+
// We have a year !
187+
if (4 == year.Length)
159188
{
160189
StringBuilder dateTimeBuilder = new StringBuilder();
161190
dateTimeBuilder.Append(year).Append("-01-01");
@@ -165,12 +194,11 @@ public DateTime Date
165194
dateTimeBuilder.Append('T');
166195
dateTimeBuilder.Append(time[..2]).Append(':');
167196
dateTimeBuilder.Append(time.Substring(2, 2)).Append(':');
168-
dateTimeBuilder.Append((6 == time.Length) ? time.Substring(4, 2) : "00");
197+
dateTimeBuilder.Append(6 == time.Length ? time.Substring(4, 2) : "00");
169198
}
170-
success = DateTime.TryParse(dateTimeBuilder.ToString(), out result);
199+
DateTime.TryParse(dateTimeBuilder.ToString(), out result);
171200
}
172201
}
173-
if (!success) result = DateTime.MinValue;
174202
}
175203
return result;
176204
}

ATL/Entities/TagData.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq;
6+
using System.Reflection;
67

78
namespace ATL
89
{
@@ -501,10 +502,11 @@ public bool hasKey(Field id)
501502

502503
/// <summary>
503504
/// Indexer
505+
/// TODO that code could be more performant and not rely on the creation of a new Map
504506
/// </summary>
505507
/// <param name="index">ATL field code to search for</param>
506508
/// <returns>Value associated with the given ATL field code</returns>
507-
public string this[Field index] => Fields.ContainsKey(index) ? Fields[index] : null;
509+
public string this[Field index] => ToMap().TryGetValue(index, out var value) ? value : null;
508510

509511
/// <summary>
510512
/// Convert non-null 'classic' fields values into a properties Map
@@ -514,9 +516,7 @@ public bool hasKey(Field id)
514516
/// <returns>Map containing all 'classic' metadata fields</returns>
515517
public IDictionary<Field, string> ToMap(bool supportsSyncLyrics = false)
516518
{
517-
IDictionary<Field, string> result = new Dictionary<Field, string>();
518-
519-
foreach (KeyValuePair<Field, string> kvp in Fields) result[kvp.Key] = kvp.Value;
519+
IDictionary<Field, string> result = new Dictionary<Field, string>(Fields);
520520

521521
if (result.ContainsKey(Field.RECORDING_DATE_OR_YEAR))
522522
{

0 commit comments

Comments
 (0)