const std = @import("std"); const zeit = @import("zeit"); const Data = @import("types.zig"); pub fn dateFmt(allocator: std.mem.Allocator, epoch: i64) ![]const u8 { var date = std.ArrayList(u8).init(allocator); try (try zeit.instant(.{ .source = .{ .unix_timestamp = @divFloor(epoch, 1_000_000) } })).time().strftime(date.writer(), "%d %b %Y, %H:%M"); return date.items; } pub fn dateCompare(self: *[]const u8, earliest: []const u8, latest: []const u8) bool { const range = if (self.len == 19) 4 else 2; const time = std.fmt.parseInt(u32, self[0..range], 10) catch 0; const etime = std.fmt.parseInt(u32, earliest[0..range], 10) catch 0; const ltime = std.fmt.parseInt(u32, latest[0..range], 10) catch 0; if (time != etime and time != ltime) { return (time > etime and time < ltime); } else { return dateCompare(self[range + 1 ..], earliest[range + 1 ..], latest[range + 1 ..]); } } pub fn scrobbleToRow(allocator: std.mem.Allocator, scrobble: Data.Scrobble) !Data.TableRow { var artistlist = std.ArrayList(Data.HyperlinkData).init(allocator); for (scrobble.artists_track) |a| { try artistlist.append(Data.HyperlinkData{ .name = a, .id = 0 }); } return Data.TableRow{ .song = .{ .name = scrobble.track, .id = 0 }, .artistlist = artistlist.items, .album = .{ .name = scrobble.album, .id = 0 }, .date = try dateFmt(allocator, scrobble.date), }; } pub fn urlDecode(allocator: std.mem.Allocator, str: []const u8) ![]const u8 { var decoded = std.ArrayList(u8).init(allocator); var i: usize = 0; while (i < str.len) : (i += 1) { const v = str[i]; if (v == '%') { if (i + 2 < str.len) { const hex = str[i + 1 .. i + 3]; const char = try std.fmt.parseInt(u8, hex, 16); try decoded.append(char); i += 2; } else return error.InvalidInput; } else try decoded.append(v); } return decoded.toOwnedSlice(); }