major: initial release

* initial development

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* pokemon

* pokemon

* pokemon

* pokemon

* pokemon

* pokemon

* improvements

* improvements

* ci/cd

* ci/cd

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

---------

Co-authored-by: sdine <sdine@sdine.com>
This commit is contained in:
Sebastian Dine
2026-05-09 11:05:47 +02:00
committed by GitHub
co-authored by sdine
parent 13262fa015
commit 55ace147bc
149 changed files with 12611 additions and 0 deletions
@@ -0,0 +1,42 @@
#pragma once
// MagicCardPreviewSource: ICardPreviewSource implementation for Magic the
// Gathering. Calls Scryfall's search endpoint at
// https://api.scryfall.com/cards/search?q=name:"<name>" AND set:<setCode>
// and returns `data[0].image_uris.normal`. Mirrors the established
// `src/components/magic/SelectedMtgPanel.tsx::getImage`, including the
// `&` -> `and` substitution in the card name.
#include "ccm/ports/ICardPreviewSource.hpp"
#include "ccm/ports/IHttpClient.hpp"
#include <string>
#include <string_view>
namespace ccm {
class MagicCardPreviewSource final : public ICardPreviewSource {
public:
explicit MagicCardPreviewSource(IHttpClient& http);
Result<std::string> fetchImageUrl(std::string_view name,
std::string_view setId,
std::string_view setNo) override;
// Build the fully URL-encoded Scryfall search URL for the given card.
// Exposed for unit testing and to keep encoding rules in one place.
static std::string buildSearchUrl(std::string_view name,
std::string_view setId);
// Parse a Scryfall /cards/search response body and pull out the
// `data[0].image_uris.normal` URL. Returns an error result when no
// matching printing is found, when the JSON is malformed, or when the
// entry has no top-level `image_uris` (double-faced cards expose them
// on a face object - no fallback in this compatibility behavior either).
static Result<std::string> parseResponse(const std::string& body);
private:
IHttpClient& http_;
};
} // namespace ccm
@@ -0,0 +1,29 @@
#pragma once
// MagicGameModule: IGameModule for Magic the Gathering. Owns its set source
// and card preview source, reports the canonical "magic" subdirectory name
// used on disk.
#include "ccm/games/IGameModule.hpp"
#include "ccm/games/magic/MagicCardPreviewSource.hpp"
#include "ccm/games/magic/MagicSetSource.hpp"
namespace ccm {
class MagicGameModule final : public IGameModule {
public:
explicit MagicGameModule(IHttpClient& http);
[[nodiscard]] Game id() const noexcept override { return Game::Magic; }
[[nodiscard]] std::string dirName() const override { return "magic"; }
[[nodiscard]] std::string displayName() const override { return "Magic"; }
ISetSource& setSource() override { return setSource_; }
ICardPreviewSource* cardPreviewSource() noexcept override { return &previewSource_; }
private:
MagicSetSource setSource_;
MagicCardPreviewSource previewSource_;
};
} // namespace ccm
@@ -0,0 +1,28 @@
#pragma once
// MagicSetSource: ISetSource implementation for Magic the Gathering.
// Calls the Scryfall API at https://api.scryfall.com/sets, drops digital-only
// sets, maps the response into our `Set` domain type, and sorts by release date
// ascending. Behavior matches `magic/set_services.rs::update_sets`.
#include "ccm/games/IGameModule.hpp"
#include "ccm/ports/IHttpClient.hpp"
namespace ccm {
class MagicSetSource final : public ISetSource {
public:
static constexpr const char* kEndpoint = "https://api.scryfall.com/sets";
explicit MagicSetSource(IHttpClient& http);
Result<std::vector<Set>> fetchAll() override;
// Pure parser exposed for unit testing without a network round-trip.
static Result<std::vector<Set>> parseResponse(const std::string& body);
private:
IHttpClient& http_;
};
} // namespace ccm