Combine searchMetadata and searchMetadataEncoded types

This commit is contained in:
mitteneer 2025-03-19 08:33:49 -04:00
parent fa46f68fd0
commit 742c3887c9

View file

@ -6,15 +6,6 @@ const Artist = Entities.Artist;
const Recording = Entities.Recording;
const Release = Entities.Release;
pub const parseOption = union(enum) {
song,
album,
artist,
all,
};
pub const parseByOptions = struct { parse: parseOption = .song, specifyBy: parseOption = .song };
pub const Result = struct {
created: ?[]const u8 = null,
count: ?u32 = null,
@ -131,116 +122,70 @@ pub const Result = struct {
}
return null;
}
//pub fn getArtistID(self: *const Result, smd: searchMetadata, parseByOption: ?parseByOptions) ?[]const u8 {
// _ = parseByOption; //
// if (self.count) |count| { // Otherwise there was an error
// switch (count) {
// 0 => return null, // No results
// 1 => {
// if (self.recordings.?[0].@"artist-credit") |acs| {
// for (acs) |ac| {
// if (std.mem.eql(u8, ac.name, smd.an)) return ac.artist.id; // Make this case/diacritic insensitive
// }
// }
// return null;
// },
// else => {
// for (self.recordings.?) |rc| {
// if (std.mem.eql(u8, rc.title, smd.tn)) { // Make this case/diacritic insensitive
// for (rc.@"artist-credit".?) |ac| {
// if (std.mem.eql(u8, ac.name, smd.an)) return ac.artist.id;
// }
// }
// }
// },
// }
// }
// return null; // Maybe return error here instead
//}
//// Not sure if I want to get a ReleaseGroup or Release yet. Start with ReleaseGroup
//pub fn getReleaseGroupID(self: *const Result, smd: searchMetadata) ?[]const u8 {
// if (self.count) |count| {
// switch (count) {
// 0 => return null,
// 1 => {
// switch (self.recordings.?[0].releases.?.len) {
// 0 => unreachable,
// 1 => return self.recordings.?[0].releases.?[0].id,
// else => {
// for (self.recordings.?[0].releases.?) |re| {
// if (std.mem.eql(u8, re.title, smd.rgn)) return re.id;
// }
// },
// }
// },
// else => { // This is not ideal, limit the number of results
// for (self.recordings.?) |rc| {
// if (std.mem.eql(u8, rc.title, smd.tn)) {
// for (rc.releases.?) |re| {
// if (std.mem.eql(u8, re.@"release-group".?.title, smd.rgn)) return re.@"release-group".?.id;
// }
// }
// }
// },
// }
// }
// return null;
//}
//pub fn getRecordingID(self: *const Result, smd: searchMetadata) ?[]const u8 {
// if (self.count) |count| {
// switch (count) {
// 0 => return null,
// 1 => return self.recordings.?[0].id,
// else => {
// const rcs: []Recording = self.recordings.?;
// //for (rcs, 0..) |rc, i| {
// // rcs[i].dt = (try zeit.instant(.{ .source = .{ .iso8601 = rc.@"first-release-date".? } })).unixTimestamp();
// //}
// std.mem.sort(Recording, rcs, {}, Recording.lessThan);
// for (rcs) |rc| {
// if (std.mem.eql(u8, smd.tn, rc.title)) {
// for (rc.@"artist-credit".?) |ac| {
// if (std.mem.eql(u8, smd.an, ac.name)) {
// for (rc.releases.?) |re| {
// if (std.mem.eql(u8, smd.rgn, re.@"release-group".?.title)) {
// //std.log.err("{s}", .{rc.id});
// return rc.id;
// }
// }
// }
// }
// }
// }
// },
// }
// }
// return null;
//}
};
pub const parseOption = union(enum) {
song,
album,
artist,
all,
};
pub const parseByOptions = struct { parse: parseOption = .song, specifyBy: parseOption = .song };
const eunuchMetadata = struct {
tn: struct { dec: []const u8, enc: []const u8 = undefined },
rn: struct { dec: []const u8, enc: []const u8 = undefined },
an: struct { dec: []const u8, enc: []const u8 = undefined },
};
// Maybe just use a HashMap...
pub const searchMetadata = struct {
tn: []const u8,
rgn: []const u8,
an: []const u8,
alloc: std.mem.Allocator = undefined,
tn: struct { dec: []const u8, enc: []const u8 = undefined },
rn: struct { dec: []const u8, enc: []const u8 = undefined },
an: struct { dec: []const u8, enc: []const u8 = undefined },
pub fn deinit(self: *searchMetadata) void {
self.alloc.free(self.tn.enc);
self.alloc.free(self.rn.enc);
self.alloc.free(self.an.enc);
}
pub fn percentEncode(self: *searchMetadata) !void {
inline for (std.meta.fields(eunuchMetadata)) |k| {
var encoded = std.ArrayList(u8).init(self.alloc);
errdefer encoded.deinit();
for (@field(self, k.name).dec) |v| {
if ((v >= 'A' and v <= 'Z') or (v >= 'a' and v <= 'z') or (v >= '0' and v <= '9') or v == '-' or v == '_' or v == '.' or v == '~') {
try encoded.append(v);
} else if (v == ' ') {
try encoded.append('+');
} else {
const hex = try std.fmt.allocPrint(self.alloc, "%{x}", .{v});
defer self.alloc.free(hex);
try encoded.appendSlice(hex);
}
}
@field(self, k.name).enc = try encoded.toOwnedSlice();
}
}
};
// I don't think I need a second type, but I'd like to hold on to the original, unencoded metadata as well, so maybe this is fine
// Maybe make fields for encoded data?
pub const searchMetadataEncoded = struct {
alloc: std.mem.Allocator,
tn: []const u8,
rgn: []const u8,
an: []const u8,
pub fn deinit(self: *const searchMetadataEncoded) void {
self.alloc.free(self.an);
self.alloc.free(self.rgn);
self.alloc.free(self.tn);
}
};
//pub const searchMetadataEncoded = struct {
// alloc: std.mem.Allocator,
// tn: []const u8,
// rgn: []const u8,
// an: []const u8,
//
// pub fn deinit(self: *const searchMetadataEncoded) void {
// self.alloc.free(self.an);
// self.alloc.free(self.rgn);
// self.alloc.free(self.tn);
// }
//};
pub const searchIDs = union {
id: []const u8,
@ -251,48 +196,26 @@ pub const searchIDs = union {
},
};
pub fn percentEncode(alloc: std.mem.Allocator, smd: searchMetadata) !searchMetadataEncoded {
var output = searchMetadataEncoded{ .alloc = alloc, .tn = undefined, .rgn = undefined, .an = undefined };
inline for (std.meta.fields(searchMetadata)) |k| {
var encoded = std.ArrayList(u8).init(alloc);
errdefer encoded.deinit();
for (@field(smd, k.name)) |v| {
if ((v >= 'A' and v <= 'Z') or (v >= 'a' and v <= 'z') or (v >= '0' and v <= '9') or v == '-' or v == '_' or v == '.' or v == '~') {
try encoded.append(v);
} else if (v == ' ') {
try encoded.append('+');
} else {
const hex = try std.fmt.allocPrint(alloc, "%{x}", .{v});
defer alloc.free(hex);
try encoded.appendSlice(hex);
}
}
@field(output, k.name) = try encoded.toOwnedSlice();
}
return output;
}
test "pe_jethro_tull" {
const test_alloc = std.testing.allocator;
const jt = searchMetadata{ .tn = "Aqualung", .rgn = "Aqualung", .an = "Jethro Tull" };
const encoded = try percentEncode(test_alloc, jt);
defer encoded.deinit();
try testing.expect(std.mem.eql(u8, encoded.an, "Jethro+Tull"));
var jt = searchMetadata{ .alloc = test_alloc, .tn = .{ .dec = "Aqualung" }, .rn = .{ .dec = "Aqualung" }, .an = .{ .dec = "Jethro Tull" } };
try jt.percentEncode();
defer jt.deinit();
try testing.expect(std.mem.eql(u8, jt.an.enc, "Jethro+Tull"));
}
test "pe_aphex_twin" {
const test_alloc = std.testing.allocator;
const at = searchMetadata{ .tn = "#3", .rgn = "Selected Ambient Works Volume II", .an = "Aphex Twin" };
const encoded = try percentEncode(test_alloc, at);
defer encoded.deinit();
try testing.expect(std.mem.eql(u8, encoded.tn, "%233"));
var at = searchMetadata{ .alloc = test_alloc, .tn = .{ .dec = "#3" }, .rn = .{ .dec = "Selected Ambient Works Volume II" }, .an = .{ .dec = "Aphex Twin" } };
try at.percentEncode();
defer at.deinit();
try testing.expect(std.mem.eql(u8, at.tn.enc, "%233"));
}
test "pe_bon_iver" {
const test_alloc = std.testing.allocator;
const bi = searchMetadata{ .tn = "21 M♢♢N WATER", .rgn = "22, a Million", .an = "Bon Iver" };
const encoded = try percentEncode(test_alloc, bi);
defer encoded.deinit();
try testing.expect(std.mem.eql(u8, encoded.tn, "21+M%e2%99%a2%e2%99%a2N+WATER"));
var bi = searchMetadata{ .alloc = test_alloc, .tn = .{ .dec = "21 M♢♢N WATER" }, .rn = .{ .dec = "22, a Million" }, .an = .{ .dec = "Bon Iver" } };
try bi.percentEncode();
defer bi.deinit();
try testing.expect(std.mem.eql(u8, bi.tn.enc, "21+M%e2%99%a2%e2%99%a2N+WATER"));
}