Deprecate original entity structs
This commit is contained in:
parent
c13c2b2817
commit
c98466b493
6 changed files with 114 additions and 525 deletions
163
src/Entities.zig
163
src/Entities.zig
|
|
@ -1,163 +0,0 @@
|
||||||
//! Types of MusicBrainz Entities described here: https://musicbrainz.org/doc/MusicBrainz_Entity
|
|
||||||
//! Fields based on JSON response fields
|
|
||||||
|
|
||||||
//const zeit = @import("zeit");
|
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
pub const Alias = struct {
|
|
||||||
@"sort-name": []const u8,
|
|
||||||
@"type-id": ?[]const u8 = null,
|
|
||||||
name: []const u8,
|
|
||||||
locale: ?[]const u8 = null,
|
|
||||||
type: ?[]const u8 = null,
|
|
||||||
primary: ?bool = null,
|
|
||||||
@"begin-date": ?[]const u8 = null,
|
|
||||||
@"end-date": ?[]const u8 = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Artist = struct {
|
|
||||||
id: []const u8,
|
|
||||||
name: []const u8,
|
|
||||||
@"sort-name": []const u8,
|
|
||||||
//sort_name: []const u8,
|
|
||||||
aliases: ?[]Alias = null,
|
|
||||||
disambiguation: ?[]const u8 = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ArtistCredit = struct {
|
|
||||||
joinphrase: ?[]const u8 = null,
|
|
||||||
name: []const u8,
|
|
||||||
artist: Artist,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Recording = struct {
|
|
||||||
id: []const u8,
|
|
||||||
score: u8,
|
|
||||||
title: []const u8,
|
|
||||||
length: ?u64 = null,
|
|
||||||
video: ?bool = null,
|
|
||||||
@"artist-credit": ?[]ArtistCredit = null,
|
|
||||||
//artist_credit: []ArtistCredit,
|
|
||||||
@"first-release-date": ?[]const u8 = null,
|
|
||||||
//dt: ?i64 = null,
|
|
||||||
//@"first-release-date": ?union(enum) { date: []const u8, dt: zeit.Date } = null,
|
|
||||||
//first_release_date: []const u8,
|
|
||||||
releases: ?[]Release = null,
|
|
||||||
isrcs: ?[][]const u8 = null,
|
|
||||||
tags: ?[]Tag = null,
|
|
||||||
disambiguation: ?[]const u8 = null,
|
|
||||||
|
|
||||||
pub fn lessThan(context: void, a: Recording, b: Recording) bool {
|
|
||||||
_ = context; // Idk what this is but it's in the Zig docs
|
|
||||||
if (a.@"first-release-date") |adtstr| {
|
|
||||||
if (b.@"first-release-date") |bdtstr| {
|
|
||||||
const adtyr = std.fmt.parseInt(u32, adtstr[0..4], 10) catch 0; // Each `catch 0` is to avoid returning an error
|
|
||||||
const bdtyr = std.fmt.parseInt(u32, bdtstr[0..4], 10) catch 0;
|
|
||||||
if (adtyr != bdtyr) {
|
|
||||||
return adtyr < bdtyr;
|
|
||||||
} else if (adtstr.len >= 7) {
|
|
||||||
if (bdtstr.len < 7) return true; // a provides more information
|
|
||||||
const adtmn = std.fmt.parseInt(u32, adtstr[5..7], 10) catch 0;
|
|
||||||
const bdtmn = std.fmt.parseInt(u32, bdtstr[5..7], 10) catch 0;
|
|
||||||
if (adtmn != bdtmn) {
|
|
||||||
return adtmn < bdtmn;
|
|
||||||
} else if (adtstr.len == 10) {
|
|
||||||
if (bdtstr.len < 10) return true; // a provides more information
|
|
||||||
const adtdy = std.fmt.parseInt(u32, adtstr[8..10], 10) catch 0;
|
|
||||||
const bdtdy = std.fmt.parseInt(u32, bdtstr[8..10], 10) catch 0;
|
|
||||||
return adtdy < bdtdy;
|
|
||||||
} else return false; // Either b provides more information, or they're the same date
|
|
||||||
} else return false; // Either b provides more information, or they're the same date
|
|
||||||
} else return true; // b provides no information
|
|
||||||
} else return false; // a provides no information
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const Release = struct {
|
|
||||||
id: []const u8,
|
|
||||||
@"status-id": ?[]const u8 = null,
|
|
||||||
//status_id: ?[]const u8 = null,
|
|
||||||
count: u8,
|
|
||||||
title: []const u8,
|
|
||||||
@"artist-credit": ?[]ArtistCredit = null,
|
|
||||||
//artist_credit: []ArtistCredit,
|
|
||||||
@"release-group": ?ReleaseGroup = null,
|
|
||||||
//release_group: ReleaseGroup,
|
|
||||||
@"track-count": u16,
|
|
||||||
//track_count: u8,
|
|
||||||
media: ?[]Medium = null,
|
|
||||||
status: ?[]const u8 = null,
|
|
||||||
date: ?[]const u8 = null,
|
|
||||||
country: ?[]const u8 = null,
|
|
||||||
@"release-events": ?[]ReleaseEvent = null,
|
|
||||||
//release_events: ?[]ReleaseEvent = null,
|
|
||||||
disambiguation: ?[]const u8 = null,
|
|
||||||
|
|
||||||
pub fn lessThan(context: void, a: Release, b: Release) bool {
|
|
||||||
_ = context; // Idk what this is but it's in the Zig docs
|
|
||||||
if (a.date) |adtstr| {
|
|
||||||
if (b.date) |bdtstr| {
|
|
||||||
const adtyr = std.fmt.parseInt(u32, adtstr[0..4], 10) catch 0; // Each `catch 0` is to avoid returning an error
|
|
||||||
const bdtyr = std.fmt.parseInt(u32, bdtstr[0..4], 10) catch 0;
|
|
||||||
if (adtyr != bdtyr) {
|
|
||||||
return adtyr < bdtyr;
|
|
||||||
} else if (adtstr.len >= 7) {
|
|
||||||
if (bdtstr.len < 7) return true; // a provides more information
|
|
||||||
const adtmn = std.fmt.parseInt(u32, adtstr[5..7], 10) catch 0;
|
|
||||||
const bdtmn = std.fmt.parseInt(u32, bdtstr[5..7], 10) catch 0;
|
|
||||||
if (adtmn != bdtmn) {
|
|
||||||
return adtmn < bdtmn;
|
|
||||||
} else if (adtstr.len == 10) {
|
|
||||||
if (bdtstr.len < 10) return true; // a provides more information
|
|
||||||
const adtdy = std.fmt.parseInt(u32, adtstr[8..10], 10) catch 0;
|
|
||||||
const bdtdy = std.fmt.parseInt(u32, bdtstr[8..10], 10) catch 0;
|
|
||||||
return adtdy < bdtdy;
|
|
||||||
} else return false; // Either b provides more information, or they're the same date
|
|
||||||
} else return false; // Either b provides more information, or they're the same date
|
|
||||||
} else return true; // b provides no information
|
|
||||||
} else return false; // a provides no information
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const Medium = struct {
|
|
||||||
position: ?u32 = null,
|
|
||||||
format: ?[]const u8 = null,
|
|
||||||
track: ?[]Track = null,
|
|
||||||
@"track-count": u32,
|
|
||||||
//track_count: u8,
|
|
||||||
@"track-offset": ?u32 = null,
|
|
||||||
//track_offset: u8,
|
|
||||||
};
|
|
||||||
pub const Track = struct {
|
|
||||||
id: []const u8,
|
|
||||||
number: []const u8,
|
|
||||||
title: []const u8,
|
|
||||||
length: ?u64 = null,
|
|
||||||
};
|
|
||||||
pub const Area = struct {
|
|
||||||
id: []const u8,
|
|
||||||
name: []const u8,
|
|
||||||
@"sort-name": []const u8,
|
|
||||||
//sort_name: []const u8,
|
|
||||||
@"iso-3166-1-codes": ?[][]const u8 = null,
|
|
||||||
//iso_3166_1_codes: [][]const u8,
|
|
||||||
};
|
|
||||||
pub const ReleaseEvent = struct {
|
|
||||||
date: []const u8,
|
|
||||||
area: Area,
|
|
||||||
};
|
|
||||||
pub const ReleaseGroup = struct {
|
|
||||||
id: []const u8,
|
|
||||||
@"type-id": ?[]const u8 = null,
|
|
||||||
//type_id: []const u8,
|
|
||||||
@"primary-type-id": ?[]const u8 = null,
|
|
||||||
//primary_type_id: []const u8,
|
|
||||||
title: []const u8,
|
|
||||||
@"primary-type": ?[]const u8 = null,
|
|
||||||
//primary_type: []const u8,
|
|
||||||
@"secondary-types": ?[][]const u8 = null,
|
|
||||||
@"secondary-type-ids": ?[][]const u8 = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Tag = struct {
|
|
||||||
count: u8,
|
|
||||||
name: []const u8,
|
|
||||||
};
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const testing = std.testing;
|
|
||||||
|
|
||||||
const Entities = @import("Entities.zig");
|
|
||||||
const Artist = Entities.Artist;
|
|
||||||
const Recording = Entities.Recording;
|
|
||||||
const Release = Entities.Release;
|
|
||||||
|
|
||||||
pub const Result = struct {
|
|
||||||
created: []const u8,
|
|
||||||
count: u32,
|
|
||||||
offset: u32,
|
|
||||||
recordings: []Recording,
|
|
||||||
|
|
||||||
pub fn getIDs(self: *const Result, smd: searchMetadata, pbo: parseByOptions) ?searchIDs {
|
|
||||||
if (self.count == 0) return null;
|
|
||||||
const sorted_recordings = self.recordings;
|
|
||||||
std.mem.sort(Recording, sorted_recordings, {}, Recording.lessThan);
|
|
||||||
for (sorted_recordings) |rc| {
|
|
||||||
switch (pbo.parse) {
|
|
||||||
.song => {
|
|
||||||
const output = searchIDs{
|
|
||||||
.id = switch (pbo.specifyBy) {
|
|
||||||
.song => song_song: {
|
|
||||||
if (std.mem.eql(u8, rc.title, smd.tn)) {
|
|
||||||
break :song_song rc.id;
|
|
||||||
//break :rc_loop;
|
|
||||||
} else break :song_song "";
|
|
||||||
},
|
|
||||||
.album => song_album: {
|
|
||||||
if (rc.releases) |rls| {
|
|
||||||
for (rls) |rl| {
|
|
||||||
if (std.mem.eql(u8, rl.title, smd.rn)) {
|
|
||||||
break :song_album rc.id;
|
|
||||||
//break :rc_loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break :song_album "";
|
|
||||||
} else {
|
|
||||||
std.log.err("Could not find any releases", .{});
|
|
||||||
break :song_album "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.artist => song_artist: {
|
|
||||||
if (rc.@"artist-credit") |acs| {
|
|
||||||
for (acs) |ac| {
|
|
||||||
if (std.mem.eql(u8, ac.name, smd.an)) {
|
|
||||||
break :song_artist rc.id;
|
|
||||||
//break :rc_loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break :song_artist "";
|
|
||||||
} else {
|
|
||||||
std.log.err("Could not find any artists", .{});
|
|
||||||
break :song_artist "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.all => unreachable, // I'll do this later
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return output;
|
|
||||||
},
|
|
||||||
.album => {
|
|
||||||
const output = searchIDs{ .id = blk: {
|
|
||||||
if (rc.releases) |rls| {
|
|
||||||
const sorted_releases = rls;
|
|
||||||
std.mem.sort(Release, sorted_releases, {}, Release.lessThan);
|
|
||||||
for (sorted_releases) |rl| {
|
|
||||||
switch (pbo.specifyBy) {
|
|
||||||
.song, .album => {
|
|
||||||
if (std.mem.eql(u8, rl.title, smd.rn)) break :blk rl.id;
|
|
||||||
},
|
|
||||||
.artist => {
|
|
||||||
if (rl.@"artist-credit") |acs| {
|
|
||||||
for (acs) |ac| {
|
|
||||||
if (std.mem.eql(u8, ac.name, smd.an)) break :blk rl.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.all => unreachable,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break :blk "";
|
|
||||||
} else break :blk "";
|
|
||||||
} };
|
|
||||||
return output;
|
|
||||||
},
|
|
||||||
.artist => {
|
|
||||||
const output = searchIDs{ .id = switch (pbo.specifyBy) {
|
|
||||||
.song, .artist => blk: {
|
|
||||||
if (rc.@"artist-credit") |acs| {
|
|
||||||
for (acs) |ac| {
|
|
||||||
if (std.mem.eql(u8, ac.name, smd.an)) break :blk ac.artist.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break :blk "";
|
|
||||||
},
|
|
||||||
.album => blk: {
|
|
||||||
if (rc.releases) |rls| {
|
|
||||||
for (rls) |rl| {
|
|
||||||
if (rl.@"artist-credit") |acs| {
|
|
||||||
for (acs) |ac| {
|
|
||||||
if (std.mem.eql(u8, ac.name, smd.an)) break :blk ac.artist.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break :blk "";
|
|
||||||
},
|
|
||||||
.all => unreachable,
|
|
||||||
} };
|
|
||||||
return output;
|
|
||||||
},
|
|
||||||
.all => {
|
|
||||||
var output = searchIDs{ .ids = undefined };
|
|
||||||
if (self.getIDs(smd, .{ .parse = .song })) |ids| output.ids.song_id = ids.id;
|
|
||||||
if (self.getIDs(smd, .{ .parse = .album })) |ids| output.ids.album_id = ids.id;
|
|
||||||
if (self.getIDs(smd, .{ .parse = .artist })) |ids| output.ids.artist_id = ids.id;
|
|
||||||
return output;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const parseOption = union(enum) {
|
|
||||||
song,
|
|
||||||
album,
|
|
||||||
artist,
|
|
||||||
all,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const parseByOptions = struct { parse: parseOption = .song, specifyBy: parseOption = .song };
|
|
||||||
|
|
||||||
pub const searchMetadata = struct {
|
|
||||||
tn: []const u8,
|
|
||||||
rn: []const u8,
|
|
||||||
an: []const u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const searchIDs = union {
|
|
||||||
id: []const u8,
|
|
||||||
ids: struct {
|
|
||||||
artist_id: ?[]const u8,
|
|
||||||
album_id: ?[]const u8,
|
|
||||||
song_id: ?[]const u8,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
100
src/QueryEntities.zig
Normal file
100
src/QueryEntities.zig
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Entities = @import("MusicBrainzEntities.zig");
|
||||||
|
const Recording = Entities.Recording;
|
||||||
|
const Release = Entities.Release;
|
||||||
|
|
||||||
|
pub const Result = struct {
|
||||||
|
created: []const u8,
|
||||||
|
count: u32,
|
||||||
|
offset: u32,
|
||||||
|
recordings: []Recording,
|
||||||
|
|
||||||
|
// There are two ways of getting information about songs and albums: the canonical and original methods
|
||||||
|
|
||||||
|
// Canonical: The information provided is the information you want. If the song title/album title/artist
|
||||||
|
// name matches, return the respective ID. This will fail often when phrases like "Remastered" are in
|
||||||
|
// song/album title, or when multiple artists are listed in a scrobble, like "Billy Bragg, Wilco". I also
|
||||||
|
// haven't implemented case/diacritic insensitiv matching, so Canonical is sorta useless atm
|
||||||
|
|
||||||
|
// Original: Tries to find the oldest instance of the information listed, rather than what's explicitly
|
||||||
|
// stated. Thus, if you search for a song coming from a compilation album (say, Yesterday on the Beatles
|
||||||
|
// album "1"), it will instead give you the information from the album the song originally appeared on
|
||||||
|
// (in this case, the album "Help!").
|
||||||
|
|
||||||
|
pub fn getID(self: *const Result, smd: SearchMetadata, pbo: ParseOption) ?[]const u8 {
|
||||||
|
if (self.count == 0) return null;
|
||||||
|
switch (pbo) {
|
||||||
|
.song => |method| {
|
||||||
|
const recordings = self.recordings;
|
||||||
|
switch (method) {
|
||||||
|
.orig => std.mem.sort(Recording, recordings, {}, Recording.lessThan),
|
||||||
|
.canon => {},
|
||||||
|
}
|
||||||
|
for (recordings) |rc| {
|
||||||
|
if (std.mem.eql(u8, rc.title, smd.tn)) {
|
||||||
|
if (method == .orig) {
|
||||||
|
return rc.id;
|
||||||
|
} else {
|
||||||
|
const artist_match: bool = artist_search: for (rc.@"artist-credit") |ac| {
|
||||||
|
if (std.mem.eql(u8, ac.name, smd.an)) break :artist_search true;
|
||||||
|
} else false; // Does this even make sense?
|
||||||
|
|
||||||
|
const album_match: bool = album_search: for (rc.releases) |rl| {
|
||||||
|
if (std.mem.eql(u8, rl.title, smd.rn)) break :album_search true;
|
||||||
|
} else false;
|
||||||
|
|
||||||
|
if (artist_match and album_match) return rc.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recordings[0].id;
|
||||||
|
},
|
||||||
|
.album => |method| {
|
||||||
|
const recordings = self.recordings;
|
||||||
|
// This sorting is probably not necessary
|
||||||
|
switch (method) {
|
||||||
|
.orig => std.mem.sort(Recording, recordings, {}, Recording.lessThan),
|
||||||
|
.canon => {},
|
||||||
|
}
|
||||||
|
song_loop: for (recordings) |rc| {
|
||||||
|
const releases = rc.releases;
|
||||||
|
switch (pbo.album) {
|
||||||
|
.orig => std.mem.sort(Release, releases, {}, Release.lessThan),
|
||||||
|
.canon => {
|
||||||
|
if (!std.mem.eql(u8, rc.title, smd.tn)) continue :song_loop;
|
||||||
|
for (rc.@"artist-credit") |ac| {
|
||||||
|
if (!std.mem.eql(u8, ac.name, smd.an)) continue :song_loop;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for (releases) |rl| {
|
||||||
|
if (std.mem.eql(u8, rl.title, smd.rn)) return rl.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return recordings[0].releases[0].id;
|
||||||
|
},
|
||||||
|
.artist => {
|
||||||
|
for (self.recordings) |rc| {
|
||||||
|
for (rc.@"artist-credit") |ac| {
|
||||||
|
if (std.mem.eql(u8, ac.name, smd.an)) return ac.artist.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self.recordings[0].@"artist-credit"[0].artist.id;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ParseOption = union(enum) {
|
||||||
|
song: enum { canon, orig },
|
||||||
|
album: enum { canon, orig },
|
||||||
|
artist,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SearchMetadata = struct {
|
||||||
|
tn: []const u8,
|
||||||
|
rn: []const u8,
|
||||||
|
an: []const u8,
|
||||||
|
};
|
||||||
|
|
@ -1,198 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const testing = std.testing;
|
|
||||||
|
|
||||||
//const Entities = @import("Entities.zig");
|
|
||||||
const Entities = @import("StrippedEntities.zig");
|
|
||||||
const Artist = Entities.Artist;
|
|
||||||
const Recording = Entities.Recording;
|
|
||||||
const Release = Entities.Release;
|
|
||||||
|
|
||||||
pub const Result = struct {
|
|
||||||
created: []const u8,
|
|
||||||
count: u32,
|
|
||||||
offset: u32,
|
|
||||||
recordings: []Recording,
|
|
||||||
|
|
||||||
// There are two ways of getting information about songs and albums: the canonical and original methods
|
|
||||||
|
|
||||||
// Canonical: The information provided is the information you want. If the song title/album title/artist
|
|
||||||
// name matches, return the respective ID. This will fail often when phrases like "Remastered" are in
|
|
||||||
// song/album title, or when multiple artists are listed in a scrobble, like "Billy Bragg, Wilco". I also
|
|
||||||
// haven't implemented case/diacritic insensitiv matching, so Canonical is sorta useless atm
|
|
||||||
|
|
||||||
// Original: Tries to find the oldest instance of the information listed, rather than what's explicitly
|
|
||||||
// stated. Thus, if you search for a song coming from a compilation album (say, Yesterday on the Beatles
|
|
||||||
// album "1"), it will instead give you the information from the album the song originally appeared on
|
|
||||||
// (in this case, the album "Help!").
|
|
||||||
|
|
||||||
pub fn getID(self: *const Result, smd: searchMetadata, pbo: parseOption) ?[]const u8 {
|
|
||||||
if (self.count == 0) return null;
|
|
||||||
switch (pbo) {
|
|
||||||
.song => |method| {
|
|
||||||
const recordings = self.recordings;
|
|
||||||
switch (method) {
|
|
||||||
.orig => std.mem.sort(Recording, recordings, {}, Recording.lessThan),
|
|
||||||
.canon => {},
|
|
||||||
}
|
|
||||||
for (recordings) |rc| {
|
|
||||||
if (std.mem.eql(u8, rc.title, smd.tn)) {
|
|
||||||
if (method == .orig) {
|
|
||||||
return rc.id;
|
|
||||||
} else {
|
|
||||||
const artist_match: bool = artist_search: for (rc.@"artist-credit") |ac| {
|
|
||||||
if (std.mem.eql(u8, ac.name, smd.an)) break :artist_search true;
|
|
||||||
} else false; // Does this even make sense?
|
|
||||||
|
|
||||||
const album_match: bool = album_search: for (rc.releases) |rl| {
|
|
||||||
if (std.mem.eql(u8, rl.title, smd.rn)) break :album_search true;
|
|
||||||
} else false;
|
|
||||||
|
|
||||||
if (artist_match and album_match) return rc.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return recordings[0].id;
|
|
||||||
},
|
|
||||||
.album => |method| {
|
|
||||||
const recordings = self.recordings;
|
|
||||||
// This sorting is probably not necessary
|
|
||||||
switch (method) {
|
|
||||||
.orig => std.mem.sort(Recording, recordings, {}, Recording.lessThan),
|
|
||||||
.canon => {},
|
|
||||||
}
|
|
||||||
song_loop: for (recordings) |rc| {
|
|
||||||
const releases = rc.releases;
|
|
||||||
switch (pbo.album) {
|
|
||||||
.orig => std.mem.sort(Release, releases, {}, Release.lessThan),
|
|
||||||
.canon => {
|
|
||||||
if (!std.mem.eql(u8, rc.title, smd.tn)) continue :song_loop;
|
|
||||||
for (rc.@"artist-credit") |ac| {
|
|
||||||
if (!std.mem.eql(u8, ac.name, smd.an)) continue :song_loop;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for (releases) |rl| {
|
|
||||||
if (std.mem.eql(u8, rl.title, smd.rn)) return rl.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return recordings[0].releases[0].id;
|
|
||||||
},
|
|
||||||
.artist => {
|
|
||||||
for (self.recordings) |rc| {
|
|
||||||
for (rc.@"artist-credit") |ac| {
|
|
||||||
if (std.mem.eql(u8, ac.name, smd.an)) return ac.artist.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return self.recordings[0].@"artist-credit"[0].artist.id;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//pub fn getIDs(self: *const Result, smd: searchMetadata, pbo: parseByOptions) ?searchIDs {
|
|
||||||
// if (self.count == 0) return null;
|
|
||||||
// const sorted_recordings = self.recordings;
|
|
||||||
// std.mem.sort(Recording, sorted_recordings, {}, Recording.lessThan);
|
|
||||||
// for (sorted_recordings) |rc| {
|
|
||||||
// switch (pbo.parse) {
|
|
||||||
// .song => {
|
|
||||||
// const output = searchIDs{
|
|
||||||
// .id = switch (pbo.specifyBy) {
|
|
||||||
// .song => song_song: {
|
|
||||||
// if (std.mem.eql(u8, rc.title, smd.tn)) {
|
|
||||||
// break :song_song rc.id;
|
|
||||||
// //break :rc_loop;
|
|
||||||
// } else break :song_song "";
|
|
||||||
// },
|
|
||||||
// .album => song_album: {
|
|
||||||
// for (rc.releases) |rl| {
|
|
||||||
// if (std.mem.eql(u8, rl.title, smd.rn)) {
|
|
||||||
// break :song_album rc.id;
|
|
||||||
// //break :rc_loop;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// break :song_album "";
|
|
||||||
// },
|
|
||||||
// .artist => song_artist: {
|
|
||||||
// for (rc.@"artist-credit") |ac| {
|
|
||||||
// if (std.mem.eql(u8, ac.name, smd.an)) {
|
|
||||||
// break :song_artist rc.id;
|
|
||||||
// //break :rc_loop;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// break :song_artist "";
|
|
||||||
// },
|
|
||||||
// .all => unreachable, // I'll do this later
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// return output;
|
|
||||||
// },
|
|
||||||
// .album => {
|
|
||||||
// const output = searchIDs{ .id = blk: {
|
|
||||||
// const sorted_releases = rc.releases;
|
|
||||||
// std.mem.sort(Release, sorted_releases, {}, Release.lessThan);
|
|
||||||
// for (sorted_releases) |rl| {
|
|
||||||
// switch (pbo.specifyBy) {
|
|
||||||
// .song, .album => {
|
|
||||||
// if (std.mem.eql(u8, rl.title, smd.rn)) break :blk rl.id;
|
|
||||||
// },
|
|
||||||
// .artist => {
|
|
||||||
// for (rl.@"artist-credit") |ac| {
|
|
||||||
// if (std.mem.eql(u8, ac.name, smd.an)) break :blk rl.id;
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// .all => unreachable,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// break :blk "";
|
|
||||||
// } };
|
|
||||||
// return output;
|
|
||||||
// },
|
|
||||||
// .artist => {
|
|
||||||
// const output = searchIDs{ .id = switch (pbo.specifyBy) {
|
|
||||||
// .song, .artist => blk: {
|
|
||||||
// for (rc.@"artist-credit") |ac| {
|
|
||||||
// if (std.mem.eql(u8, ac.name, smd.an)) break :blk ac.artist.id;
|
|
||||||
// }
|
|
||||||
// break :blk "";
|
|
||||||
// },
|
|
||||||
// .album => blk: {
|
|
||||||
// for (rc.releases) |rl| {
|
|
||||||
// for (rl.@"artist-credit") |ac| {
|
|
||||||
// if (std.mem.eql(u8, ac.name, smd.an)) break :blk ac.artist.id;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// break :blk "";
|
|
||||||
// },
|
|
||||||
// .all => unreachable,
|
|
||||||
// } };
|
|
||||||
// return output;
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
//}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const parseOption = union(enum) {
|
|
||||||
song: enum { canon, orig },
|
|
||||||
album: enum { canon, orig },
|
|
||||||
artist,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const parseByOptions = struct { parse: parseOption = .song, specifyBy: parseOption = .song };
|
|
||||||
|
|
||||||
pub const searchMetadata = struct {
|
|
||||||
tn: []const u8,
|
|
||||||
rn: []const u8,
|
|
||||||
an: []const u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const searchIDs = union {
|
|
||||||
id: []const u8,
|
|
||||||
ids: struct {
|
|
||||||
artist_id: ?[]const u8,
|
|
||||||
album_id: ?[]const u8,
|
|
||||||
song_id: ?[]const u8,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
29
src/root.zig
29
src/root.zig
|
|
@ -1,17 +1,16 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const Entities = @import("Entities.zig");
|
|
||||||
const Alias = @import("Alias.zig");
|
|
||||||
const MBQ = @import("MusicBrainzQuery.zig");
|
|
||||||
const Client = std.http.Client;
|
const Client = std.http.Client;
|
||||||
const SE = @import("StrippedEntities.zig");
|
|
||||||
const SMBQ = @import("StrippedMBQ.zig");
|
const QE = @import("QueryEntities.zig");
|
||||||
|
const SearchMetadata = QE.SearchMetadata;
|
||||||
|
const Result = QE.Result;
|
||||||
|
|
||||||
pub const user_agent: []const u8 = "ZuletztMBClient/0.0.1 (swebbguy@gmail.com)";
|
pub const user_agent: []const u8 = "ZuletztMBClient/0.0.1 (swebbguy@gmail.com)";
|
||||||
|
|
||||||
pub fn mbSearch(alloc: std.mem.Allocator, smd: SMBQ.searchMetadata) !SMBQ.Result {
|
pub fn mbSearch(alloc: std.mem.Allocator, smd: SearchMetadata) !Result {
|
||||||
var encoded: SMBQ.searchMetadata = undefined;
|
var encoded: SearchMetadata = undefined;
|
||||||
inline for (std.meta.fields(SMBQ.searchMetadata)) |k| {
|
inline for (std.meta.fields(SearchMetadata)) |k| {
|
||||||
var code = std.ArrayList(u8).init(alloc);
|
var code = std.ArrayList(u8).init(alloc);
|
||||||
errdefer code.deinit();
|
errdefer code.deinit();
|
||||||
for (@field(smd, k.name)) |v| {
|
for (@field(smd, k.name)) |v| {
|
||||||
|
|
@ -53,7 +52,7 @@ pub fn mbSearch(alloc: std.mem.Allocator, smd: SMBQ.searchMetadata) !SMBQ.Result
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
const json = try std.json.parseFromSliceLeaky(SMBQ.Result, alloc, ar.items, .{ .ignore_unknown_fields = true });
|
const json = try std.json.parseFromSliceLeaky(Result, alloc, ar.items, .{ .ignore_unknown_fields = true });
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +62,7 @@ test "arid_via_recording" {
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const test_alloc = arena.allocator();
|
const test_alloc = arena.allocator();
|
||||||
|
|
||||||
const metadata = SMBQ.searchMetadata{ .tn = "Veni veni Emmanuel", .an = "iamthemorning", .rn = "Counting the Ghosts" };
|
const metadata = SearchMetadata{ .tn = "Veni veni Emmanuel", .an = "iamthemorning", .rn = "Counting the Ghosts" };
|
||||||
const iatm_id: []const u8 = "5854a6de-af8f-4b99-8710-cb47d6436a19";
|
const iatm_id: []const u8 = "5854a6de-af8f-4b99-8710-cb47d6436a19";
|
||||||
|
|
||||||
const search_result = try mbSearch(test_alloc, metadata);
|
const search_result = try mbSearch(test_alloc, metadata);
|
||||||
|
|
@ -84,7 +83,7 @@ test "arid_via_recording_multiple_artists_1" {
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const test_alloc = arena.allocator();
|
const test_alloc = arena.allocator();
|
||||||
|
|
||||||
const metadata = SMBQ.searchMetadata{ .tn = "Roll Me Up And Smoke Me When I Die", .an = "Lyle Lovett", .rn = "Willie Nelson American Outlaw" };
|
const metadata = SearchMetadata{ .tn = "Roll Me Up And Smoke Me When I Die", .an = "Lyle Lovett", .rn = "Willie Nelson American Outlaw" };
|
||||||
const ll_id: []const u8 = "7241e3ed-5ad4-4849-94df-6858ea833472";
|
const ll_id: []const u8 = "7241e3ed-5ad4-4849-94df-6858ea833472";
|
||||||
|
|
||||||
const search_result = try mbSearch(test_alloc, metadata);
|
const search_result = try mbSearch(test_alloc, metadata);
|
||||||
|
|
@ -103,7 +102,7 @@ test "rgid_via_recording" {
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const test_alloc = arena.allocator();
|
const test_alloc = arena.allocator();
|
||||||
|
|
||||||
const metadata = SMBQ.searchMetadata{ .tn = "I Of The Storm", .rn = "Beneath the Skin", .an = "Of Monsters and Men" };
|
const metadata = SearchMetadata{ .tn = "I Of The Storm", .rn = "Beneath the Skin", .an = "Of Monsters and Men" };
|
||||||
const bts_id: []const u8 = "4f4f5b98-45ac-4b47-addb-66b501473bd8";
|
const bts_id: []const u8 = "4f4f5b98-45ac-4b47-addb-66b501473bd8";
|
||||||
|
|
||||||
const search_result = try mbSearch(test_alloc, metadata);
|
const search_result = try mbSearch(test_alloc, metadata);
|
||||||
|
|
@ -122,7 +121,7 @@ test "rgid_via_recording_multiple_artists_2" {
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const test_alloc = arena.allocator();
|
const test_alloc = arena.allocator();
|
||||||
|
|
||||||
const metadata = SMBQ.searchMetadata{ .tn = "Hesitating Beauty", .rn = "Mermaid Avenue", .an = "Wilco" };
|
const metadata = SearchMetadata{ .tn = "Hesitating Beauty", .rn = "Mermaid Avenue", .an = "Wilco" };
|
||||||
const wilco_id: []const u8 = "9ba73bf8-6c15-4bd2-8da1-e2292538f617";
|
const wilco_id: []const u8 = "9ba73bf8-6c15-4bd2-8da1-e2292538f617";
|
||||||
|
|
||||||
const search_result = try mbSearch(test_alloc, metadata);
|
const search_result = try mbSearch(test_alloc, metadata);
|
||||||
|
|
@ -140,7 +139,7 @@ test "rid_aqualung" {
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const test_alloc = arena.allocator();
|
const test_alloc = arena.allocator();
|
||||||
|
|
||||||
const metadata = SMBQ.searchMetadata{ .tn = "Aqualung", .rn = "Aqualung", .an = "Jethro Tull" };
|
const metadata = SearchMetadata{ .tn = "Aqualung", .rn = "Aqualung", .an = "Jethro Tull" };
|
||||||
const aqualung_id: []const u8 = "2621d113-3a9f-41f9-a0f2-b9459f86e8e9";
|
const aqualung_id: []const u8 = "2621d113-3a9f-41f9-a0f2-b9459f86e8e9";
|
||||||
|
|
||||||
const search_result = try mbSearch(test_alloc, metadata);
|
const search_result = try mbSearch(test_alloc, metadata);
|
||||||
|
|
@ -157,7 +156,7 @@ test "rid_battery" {
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const test_alloc = arena.allocator();
|
const test_alloc = arena.allocator();
|
||||||
|
|
||||||
const metadata = SMBQ.searchMetadata{ .tn = "Battery", .rn = "Master of Puppets", .an = "Metallica" };
|
const metadata = SearchMetadata{ .tn = "Battery", .rn = "Master of Puppets", .an = "Metallica" };
|
||||||
const battery_id: []const u8 = "3bfda26a-49fa-4bc4-a4d6-8bbfa0767ab7";
|
const battery_id: []const u8 = "3bfda26a-49fa-4bc4-a4d6-8bbfa0767ab7";
|
||||||
|
|
||||||
const search_result = try mbSearch(test_alloc, metadata);
|
const search_result = try mbSearch(test_alloc, metadata);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue