From ada1c12f573de7ca51c509e27d4866a20a312c46 Mon Sep 17 00:00:00 2001 From: cdricms <36056008+cdricms@users.noreply.github.com> Date: Sat, 21 Mar 2026 17:25:07 +0100 Subject: [PATCH] Started off well --- .gitignore | 8 + GEMINI.md | 6 + Package.swift | 28 + Sources/MusicBrainz/MusicBrainz.swift | 863 ++++++++++++++++++ Sources/MusicBrainzExe/main.swift | 31 + .../ExtendedSearchTests.swift | 108 +++ Tests/MusicBrainzTests/MusicBrainzTests.swift | 54 ++ Tests/MusicBrainzTests/QueryTests.swift | 36 + Tests/MusicBrainzTests/SearchTests.swift | 30 + 9 files changed, 1164 insertions(+) create mode 100644 .gitignore create mode 100644 GEMINI.md create mode 100644 Package.swift create mode 100644 Sources/MusicBrainz/MusicBrainz.swift create mode 100644 Sources/MusicBrainzExe/main.swift create mode 100644 Tests/MusicBrainzTests/ExtendedSearchTests.swift create mode 100644 Tests/MusicBrainzTests/MusicBrainzTests.swift create mode 100644 Tests/MusicBrainzTests/QueryTests.swift create mode 100644 Tests/MusicBrainzTests/SearchTests.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0023a53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..1038081 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,6 @@ +# MusicBrainz Swift + +Documentation and reference for the MusicBrainz API implementation. + +## Search API Reference +- [MusicBrainz Search API Documentation](https://musicbrainz.org/doc/MusicBrainz_API/Search) diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..c7674e6 --- /dev/null +++ b/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version: 6.2 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "MusicBrainz", + products: [ + // Products define the executables and libraries a package produces, making them visible to other packages. + .library( + name: "MusicBrainz", + targets: ["MusicBrainz"] + ), + .executable(name: "MusicBrainzExe", targets: ["MusicBrainzExe"]), + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products from dependencies. + .target( + name: "MusicBrainz" + ), + .executableTarget(name: "MusicBrainzExe", dependencies: ["MusicBrainz"]), + .testTarget( + name: "MusicBrainzTests", + dependencies: ["MusicBrainz"] + ), + ] +) diff --git a/Sources/MusicBrainz/MusicBrainz.swift b/Sources/MusicBrainz/MusicBrainz.swift new file mode 100644 index 0000000..9754f2a --- /dev/null +++ b/Sources/MusicBrainz/MusicBrainz.swift @@ -0,0 +1,863 @@ +import Foundation + +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif + +public enum MusicBrainzError: Error { + case badURL + case badServerResponse(Int) + case decodingError(Error) + case coordinator(Error) +} + +// MARK: - Generic Support + +internal struct DynamicCodingKey: CodingKey { + var stringValue: String + var intValue: Int? + init?(stringValue: String) { self.stringValue = stringValue } + init?(intValue: Int) { return nil } +} + +public enum MusicBrainzEntity: String, Sendable { + case area + case artist + case event + case instrument + case label + case place + case recording + case release + case releaseGroup = "release-group" + case series + case work + case url + + public var responseKey: String { + switch self { + case .series: return "series" + default: return "\(self.rawValue)s" + } + } +} + +public struct MusicBrainzEntityType: Sendable { + public let entity: MusicBrainzEntity + + public static var area: MusicBrainzEntityType { .init(entity: .area) } + public static var artist: MusicBrainzEntityType { .init(entity: .artist) } + public static var event: MusicBrainzEntityType { .init(entity: .event) } + public static var instrument: MusicBrainzEntityType { .init(entity: .instrument) } + public static var label: MusicBrainzEntityType