|
9 | 9 | #include "internal/json_parse.hpp" |
10 | 10 |
|
11 | 11 | using audd::internal::parse_enterprise_chunk; |
| 12 | +using audd::internal::offset_to_seconds; |
| 13 | + |
| 14 | +namespace { |
| 15 | +// flatten mirrors the chunk-flattening + offset anchoring performed in |
| 16 | +// AudD::recognize_enterprise: it walks the parsed chunks, computes each |
| 17 | +// match's absolute file position from the chunk offset plus the |
| 18 | +// fragment-relative start_offset/end_offset, and returns the flat vector. |
| 19 | +std::vector<audd::EnterpriseMatch> flatten(const nlohmann::json& result) { |
| 20 | + std::vector<audd::EnterpriseMatch> out; |
| 21 | + for (const auto& chunk : result) { |
| 22 | + auto parsed = parse_enterprise_chunk(chunk); |
| 23 | + auto base = offset_to_seconds(parsed.offset); |
| 24 | + for (auto& song : parsed.songs) { |
| 25 | + if (base) { |
| 26 | + song.start_seconds = *base + song.start_offset / 1000.0; |
| 27 | + song.end_seconds = *base + song.end_offset / 1000.0; |
| 28 | + } |
| 29 | + out.push_back(std::move(song)); |
| 30 | + } |
| 31 | + } |
| 32 | + return out; |
| 33 | +} |
| 34 | +} // namespace |
| 35 | + |
| 36 | +TEST_CASE("offset_to_seconds parses the documented offset shapes") { |
| 37 | + using doctest::Approx; |
| 38 | + CHECK_FALSE(offset_to_seconds("").has_value()); |
| 39 | + CHECK(offset_to_seconds("30").value() == Approx(30.0)); |
| 40 | + CHECK(offset_to_seconds("00:30").value() == Approx(30.0)); |
| 41 | + CHECK(offset_to_seconds("00:01:00").value() == Approx(60.0)); |
| 42 | + CHECK(offset_to_seconds("01:02:03").value() == Approx(3723.0)); |
| 43 | + CHECK(offset_to_seconds("12.5").value() == Approx(12.5)); |
| 44 | + // Unparseable -> nullopt, never throws. |
| 45 | + CHECK_FALSE(offset_to_seconds("not-a-time").has_value()); |
| 46 | + CHECK_FALSE(offset_to_seconds("1:2:3:4").has_value()); |
| 47 | + CHECK_FALSE(offset_to_seconds("00::30").has_value()); |
| 48 | +} |
| 49 | + |
| 50 | +TEST_CASE("enterprise flatten anchors start_seconds/end_seconds to the file") { |
| 51 | + using doctest::Approx; |
| 52 | + auto j = nlohmann::json::parse(R"([ |
| 53 | + { |
| 54 | + "offset": "00:01:00", |
| 55 | + "songs": [{ |
| 56 | + "artist": "Daft Punk", |
| 57 | + "title": "Get Lucky", |
| 58 | + "start_offset": 4200, |
| 59 | + "end_offset": 11800 |
| 60 | + }] |
| 61 | + }, |
| 62 | + { |
| 63 | + "songs": [{ |
| 64 | + "artist": "No Offset", |
| 65 | + "title": "Untitled", |
| 66 | + "start_offset": 500, |
| 67 | + "end_offset": 9000 |
| 68 | + }] |
| 69 | + } |
| 70 | + ])"); |
| 71 | + auto matches = flatten(j); |
| 72 | + REQUIRE(matches.size() == 2); |
| 73 | + |
| 74 | + // Chunk offset 60s + 4200ms / 11800ms fragment-relative. |
| 75 | + REQUIRE(matches[0].start_seconds.has_value()); |
| 76 | + REQUIRE(matches[0].end_seconds.has_value()); |
| 77 | + CHECK(matches[0].start_seconds.value() == Approx(64.2)); |
| 78 | + CHECK(matches[0].end_seconds.value() == Approx(71.8)); |
| 79 | + |
| 80 | + // Chunk with no offset -> seconds stay absent; raw offsets still present. |
| 81 | + CHECK_FALSE(matches[1].start_seconds.has_value()); |
| 82 | + CHECK_FALSE(matches[1].end_seconds.has_value()); |
| 83 | + CHECK(matches[1].start_offset == 500); |
| 84 | + CHECK(matches[1].end_offset == 9000); |
| 85 | +} |
12 | 86 |
|
13 | 87 | TEST_CASE("enterprise chunk parses songs array") { |
14 | 88 | auto j = nlohmann::json::parse(R"({ |
|
0 commit comments