mtgban

package
v0.0.0-...-1e91090 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 2, 2024 License: MIT Imports: 16 Imported by: 4

Documentation

Overview

Package mtgban defines interfaces for scrapers and utility functions to obtain pricing information from various vendors.

Index

Constants

View Source
const (
	DefaultArbitMinDiff      = 0.2
	DefaultArbitMinSpread    = 25.0
	DefaultMultiMinDiff      = 5.0
	DefaultMultiMinSpread    = 100.0
	DefaultMismatchMinDiff   = 1.0
	DefaultMismatchMinSpread = 100.0
)

Variables

View Source
var (
	// The base Card fields for the canonical headers
	CardHeader = []string{
		"Key", "Name", "Edition", "Finish", "Number", "Rarity",
	}

	// The canonical header that will be present in all inventory files
	InventoryHeader = append(CardHeader, "Conditions", "Price", "Quantity", "URL")

	// The canonical header that will be present in all market files
	MarketHeader = append(InventoryHeader, "Seller", "Bundle")

	// Additional fields for Markets neecessary for Carters
	CartHeader = append(MarketHeader, "Original Id", "Instance Id")

	// The canonical header that will be present in all buylist files
	BuylistHeader = append(CardHeader, "Conditions", "Buy Price", "Trade Price", "Quantity", "Price Ratio", "URL", "Vendor")

	ArbitHeader = append(CardHeader, "Conditions", "Available", "Sell Price", "Buy Price", "Trade Price", "Difference", "Spread", "Abs Difference", "Price Ratio")

	MismatchHeader = append(CardHeader, "Conditions", "Price", "Reference", "Difference", "Spread")

	MultiArbitHeader = []string{
		"Seller", "Cards", "Listings", "Total Prices", "Total Buylist", "Difference", "Spread",
	}

	MarketTotalsHeader = append(CardHeader, "Listings", "Total Quantity", "Lowest Price", "Average", "Spread")
)
View Source
var DefaultGradeTags = []string{
	"NM", "SP", "MP", "HP",
}

The default list of conditions most scrapers output

View Source
var ErrScraperNotFound = errors.New("scraper not found")
View Source
var FullGradeTags = []string{
	"NM", "SP", "MP", "HP", "PO",
}

The full list of conditions supported

Functions

func ComputeSKU

func ComputeSKU(cardId, condition string, flags ...string) (string, error)

func DateEqual

func DateEqual(date1, date2 time.Time) bool

func GetExchangeRate

func GetExchangeRate(currency string) (float64, error)

func WriteArbitrageToCSV

func WriteArbitrageToCSV(arbitrage []ArbitEntry, w io.Writer) error

func WriteBuylistToCSV

func WriteBuylistToCSV(buylist BuylistRecord, w io.Writer) error

func WriteCombineToCSV

func WriteCombineToCSV(root *CombineRoot, w io.Writer) error

func WriteInventoryToCSV

func WriteInventoryToCSV(inventory InventoryRecord, w io.Writer) error

func WriteMismatchToCSV

func WriteMismatchToCSV(mismatch []ArbitEntry, w io.Writer) error

func WriteMultiArbitrageToCSV

func WriteMultiArbitrageToCSV(multi []MultiArbitEntry, w io.Writer) error

func WritePennyToCSV

func WritePennyToCSV(penny []PennystockEntry, w io.Writer) error

func WriteScraperToJSON

func WriteScraperToJSON(scraper Scraper, w io.Writer) error

func WriteSellerToCSV

func WriteSellerToCSV(seller Seller, w io.Writer) error

func WriteSellerToJSON

func WriteSellerToJSON(seller Seller, w io.Writer) error

func WriteTotalsToCSV

func WriteTotalsToCSV(totals []MarketTotalsEntry, w io.Writer) error

func WriteVendorToCSV

func WriteVendorToCSV(vendor Vendor, w io.Writer) error

func WriteVendorToJSON

func WriteVendorToJSON(vendor Vendor, w io.Writer) error

Types

type ArbitEntry

type ArbitEntry struct {
	// ID of the card
	CardId string

	// The buylist used to determine Arbit
	BuylistEntry BuylistEntry

	// The actual entry that matches either of the above
	InventoryEntry InventoryEntry

	// The inventory used to determine Mismatch
	ReferenceEntry InventoryEntry

	// Difference of the prices
	Difference float64

	// Spread between the the prices
	Spread float64

	// Difference of the prices accounting for quantities available
	AbsoluteDifference float64

	// Amount of cards that can be applied
	Quantity int
}

func Arbit

func Arbit(opts *ArbitOpts, vendor Vendor, seller Seller) (result []ArbitEntry, err error)

func Mismatch

func Mismatch(opts *ArbitOpts, reference Seller, probe Seller) (result []ArbitEntry, err error)

type ArbitOpts

type ArbitOpts struct {
	// Extra factor to modify Inventory prices
	Rate float64

	// Minimum Inventory price
	MinPrice float64

	// Minimum Buylist price
	MinBuyPrice float64

	// Minimum difference between prices
	MinDiff float64

	// Minimum Inventory quantities
	MinQuantity int

	// Minimum spread % between prices
	MinSpread float64

	// Maximum Spread % between prices
	MaxSpread float64

	// Maximum price ratio of Inventory
	MaxPriceRatio float64

	// Use credit for Buylist prices
	UseTrades bool

	// Whether to consider foils
	NoFoil   bool
	OnlyFoil bool

	// Whether to skip non-rl cards
	OnlyReserveList bool

	// List of conditions to ignore
	Conditions []string

	// List of rarities to ignore
	Rarities []string

	// List of editions (or set codes) to ignore
	Editions []string

	// List of editions (or set codes) to select
	OnlyEditions []string

	// List of per-edition collector numbers to select
	OnlyCollectorNumberRanges map[string][2]int

	// Only run for products with static decklists
	SealedDecklist bool

	// Only select entries which are part of a bundle
	OnlyBundles bool

	// List of seller name that wil be considered
	Sellers []string

	// Custom function to be run on the card
	// It returns a custom factor to be applied on the buylist price,
	// and whether the entry shoul be skipped
	CustomCardFilter func(co *mtgmatcher.CardObject) (float64, bool)
}

type BanClient

type BanClient struct {
	// contains filtered or unexported fields
}

BanClient abstracts some common operations that can be performed on any Scraper type types, as well as offering a way to retrieve a single or multiple Scapers.

func NewClient

func NewClient() *BanClient

Return an empty BanClient

func (*BanClient) Load

func (bc *BanClient) Load() error

Load inventory and buylist content for each scraper registered in the client

func (*BanClient) Register

func (bc *BanClient) Register(scraper Scraper)

Add a Scraper to the client

func (*BanClient) RegisterMarket

func (bc *BanClient) RegisterMarket(scraper Scraper, shorthand string)

Add a Scraper to the client, enable the Market with the given shorthand

func (*BanClient) RegisterSeller

func (bc *BanClient) RegisterSeller(scraper Scraper)

Add a Scraper to the client, enable the seller side only (if any) If the added scraper is a market, it will be split into its subsellers

func (*BanClient) RegisterVendor

func (bc *BanClient) RegisterVendor(scraper Scraper)

Add a Scraper to the client, enable the vendor side only (if any)

func (*BanClient) ScraperByName

func (bc *BanClient) ScraperByName(shorthand string) (Scraper, error)

Return the scraper with a matching name from the ones registered in the client

func (*BanClient) Scrapers

func (bc *BanClient) Scrapers() (scrapers []Scraper)

Return a new slice containing all the scrapers registered in the client

func (*BanClient) Sellers

func (bc *BanClient) Sellers() (sellers []Seller)

Return a new slice containing all the sellers registered in the client

func (*BanClient) Vendors

func (bc *BanClient) Vendors() (vendors []Vendor)

Return a new slice containing all the vendors registered in the client

type BaseMarket

type BaseMarket struct {
	// contains filtered or unexported fields
}

Base structure for the conversion of a Market to a standard Seller This will hold the original Market scraper and retrieve the loaded subseller from its ScraperInfo

func (*BaseMarket) Info

func (m *BaseMarket) Info() ScraperInfo

func (*BaseMarket) Inventory

func (m *BaseMarket) Inventory() (InventoryRecord, error)

type BaseScraper

type BaseScraper struct {
	// contains filtered or unexported fields
}

func (*BaseScraper) Buylist

func (scraper *BaseScraper) Buylist() (BuylistRecord, error)

func (*BaseScraper) Info

func (scraper *BaseScraper) Info() (info ScraperInfo)

func (*BaseScraper) Inventory

func (scraper *BaseScraper) Inventory() (InventoryRecord, error)

type BaseSeller

type BaseSeller struct {
	// contains filtered or unexported fields
}

func (*BaseSeller) Info

func (seller *BaseSeller) Info() ScraperInfo

func (*BaseSeller) Inventory

func (seller *BaseSeller) Inventory() (InventoryRecord, error)

type BaseVendor

type BaseVendor struct {
	// contains filtered or unexported fields
}

func (*BaseVendor) Buylist

func (vendor *BaseVendor) Buylist() (BuylistRecord, error)

func (*BaseVendor) Info

func (vendor *BaseVendor) Info() (info ScraperInfo)

type BuylistEntry

type BuylistEntry struct {
	// Quantity of this entry
	Quantity int `json:"quantity"`

	// The grade of the current entry
	// Only supported values are listed in FullGradeTags
	// If empty it is considered "NM".
	Conditions string `json:"conditions"`

	// The price at which this entry is bought, in USD
	BuyPrice float64 `json:"buy_price"`

	// The price at which this entry is bought, in store credit
	TradePrice float64 `json:"trade_price,omitempty"`

	// The ratio between the sale and buy prices, indicating desiderability
	// of the entry by the provider
	PriceRatio float64 `json:"price_ratio,omitempty"`

	// The link for this entry on the scraper website (if available)
	URL string `json:"url"`

	// Name of the vendor providing the entry
	VendorName string `json:"vendor_name,omitempty"`

	// Original identifier as available from the scraper
	OriginalId string `json:"original_id,omitempty"`

	// Original instance identifier as available from the scraper
	// This is usually the "SKU", or the id of the entry taking into
	// account different properties, such as conditions, language etc
	InstanceId string `json:"instance_id,omitempty"`

	// Any additional custom fields set by the scraper
	CustomFields map[string]string `json:"custom_fields,omitempty"`

	// SKU id, composed of ScryfallId, language, finish, and condition
	SKUID string `json:"sku_id,omitempty"`
}

BuylistEntry represents an entry for buying a particular Card

func (BuylistEntry) Condition

func (be BuylistEntry) Condition() string

func (BuylistEntry) Pricing

func (be BuylistEntry) Pricing() float64

type BuylistRecord

type BuylistRecord map[string][]BuylistEntry

The base map for Vendor containing a uuid pointing to an array of BuylistEntry

func LoadBuylistFromCSV

func LoadBuylistFromCSV(r io.Reader, flags ...bool) (BuylistRecord, error)

func (BuylistRecord) Add

func (bl BuylistRecord) Add(cardId string, entry *BuylistEntry) error

func (BuylistRecord) AddRelaxed

func (bl BuylistRecord) AddRelaxed(cardId string, entry *BuylistEntry) error

type Carter

type Carter interface {
	// Enable the cart interface (loading the existing cart for example).
	Activate(user, pass string) error

	// Add an InventoryEntry to the online cart.
	Add(entry InventoryEntry) error
}

Carter is the inteface used to identify Seller scrapers that can add entries to the online cart of the provider.

type CombineEntry

type CombineEntry struct {
	ScraperName string
	Price       float64
	Ratio       float64
	Quantity    int
	URL         string
}

type CombineRoot

type CombineRoot struct {
	Names   []string
	Entries map[string]map[string]CombineEntry
}

func CombineBuylists

func CombineBuylists(vendors []Vendor, useCredit bool) (*CombineRoot, error)

func CombineInventories

func CombineInventories(sellers []Seller) (*CombineRoot, error)

type GenericEntry

type GenericEntry interface {
	Pricing() float64
	Condition() string
}

Interface describing common operations on entries

type InventoryEntry

type InventoryEntry struct {
	// Quantity of this entry
	Quantity int `json:"quantity"`

	// The grade of the current entry
	// Only supported values are listed in FullGradeTags
	Conditions string `json:"conditions"`

	// The price of this entry, in USD
	Price float64 `json:"price"`

	// The link for this entry on the scraper website (if available)
	URL string `json:"url"`

	// Only used for a Marketplace inventory
	SellerName string `json:"seller_name,omitempty"`

	// Part of a hub of sellers that can ship directly
	Bundle bool `json:"bundle,omitempty"`

	// Original identifier as available from the scraper
	// This is usually the "product id".
	OriginalId string `json:"original_id,omitempty"`

	// Original instance identifier as available from the scraper
	// This is usually the "SKU", or the id of the entry taking into
	// account different properties, such as conditions, language etc
	InstanceId string `json:"instance_id,omitempty"`

	// Any additional custom fields set by the scraper
	CustomFields map[string]string `json:"custom_fields,omitempty"`

	// SKU id, composed of ScryfallId, language, finish, and condition
	SKUID string `json:"sku_id,omitempty"`
}

InventoryEntry represents an entry for selling a particular Card

func (InventoryEntry) Condition

func (ie InventoryEntry) Condition() string

func (InventoryEntry) Pricing

func (ie InventoryEntry) Pricing() float64

type InventoryRecord

type InventoryRecord map[string][]InventoryEntry

The base map for Seller containing a uuid pointing to an array of InventoryEntry

func InventoryForSeller

func InventoryForSeller(seller Seller, sellerName string) (InventoryRecord, error)

Return the inventory for any given seller present in the market. If possible, it will use the Inventory() call to populate data.

func LoadInventoryFromCSV

func LoadInventoryFromCSV(r io.Reader, flags ...bool) (InventoryRecord, error)

func (InventoryRecord) Add

func (inv InventoryRecord) Add(cardId string, entry *InventoryEntry) error

Add a new record to the inventory, similar existing entries are merged

func (InventoryRecord) AddRelaxed

func (inv InventoryRecord) AddRelaxed(cardId string, entry *InventoryEntry) error

Add a new record to the inventory, existing entries are always merged

func (InventoryRecord) AddStrict

func (inv InventoryRecord) AddStrict(cardId string, entry *InventoryEntry) error

Add new record to the inventory, similar existing entries are not merged

func (InventoryRecord) AddUnique

func (inv InventoryRecord) AddUnique(cardId string, entry *InventoryEntry) error

Add new record to the inventory, if same card and condition exist, error out

type LogCallbackFunc

type LogCallbackFunc func(format string, a ...interface{})

type Market

type Market interface {
	// Return the whole inventory for a Market. If not already loaded,
	// it will start scraping the seller gathering the necessary data.
	Inventory() (InventoryRecord, error)

	// Return some information about the market
	Info() ScraperInfo

	// Return all names for the sellers present in the Market
	MarketNames() []string
}

Market is the interface describing actions to be performed on the inventory available on a platform, usually combining different sellers

type MarketTotalsEntry

type MarketTotalsEntry struct {
	CardId string

	SingleListings  int
	TotalQuantities int

	Lowest  float64
	Average float64
	Spread  float64
}

func MarketTotals

func MarketTotals(opts *MarketTotalsOptions, market Market) (result []MarketTotalsEntry, err error)

type MarketTotalsOptions

type MarketTotalsOptions struct {
	FilterFunc func(cardId string) bool
}

type MultiArbitEntry

type MultiArbitEntry struct {
	SellerName string
	VendorName string

	Quantity int
	Entries  []ArbitEntry

	Price        float64
	BuylistPrice float64

	Difference float64
	Spread     float64
}

func MultiArbit

func MultiArbit(opts *MultiArbitOpts, vendor Vendor, market Market) (result []MultiArbitEntry, err error)

type MultiArbitOpts

type MultiArbitOpts struct {
	Options *ArbitOpts
	Extra   float64

	MinDifference float64
	MinSpread     float64
}

type PennystockEntry

type PennystockEntry struct {
	CardId string
	InventoryEntry
}

func Pennystock

func Pennystock(seller Seller, full bool) (result []PennystockEntry, err error)

type Scraper

type Scraper interface {
	Info() ScraperInfo
}

Scraper is the interface both Sellers and Vendors need to implement

func NewScraperFromData

func NewScraperFromData(inventory InventoryRecord, buylist BuylistRecord, info ScraperInfo) Scraper

type ScraperInfo

type ScraperInfo struct {
	// Full name of the store
	Name string `json:"name"`

	// Shorthand or ID of the store
	Shorthand string `json:"shorthand"`

	// Symbol for worldwide stores
	CountryFlag string `json:"country,omitempty"`

	// Timestamp of the last Inventory() execution
	InventoryTimestamp *time.Time `json:"inventory_ts,omitempty"`

	// Timestamp of the last Buylist() execution
	BuylistTimestamp *time.Time `json:"buylist_ts,omitempty"`

	// Only index-style data is available, no quantities or conditions
	MetadataOnly bool `json:"metadata,omitempty"`

	// Vendor has no store credit bonus
	NoCredit bool `json:"no_credit,omitempty"`

	// Inventory quantities are not available
	NoQuantityInventory bool `json:"no_qty_inventory,omitempty"`

	// Scraper contains sealed information instead of singles
	SealedMode bool `json:"sealed,omitempty"`

	// Any additional custom fields set by the user
	CustomFields map[string]string `json:"custom_fields,omitempty"`
}

ScraperInfo contains

type Seller

type Seller interface {
	// Return the inventory for a Seller. If not already loaded, it will start
	// scraping the seller gathering the necessary data.
	Inventory() (InventoryRecord, error)

	// Return some information about the seller
	Info() ScraperInfo
}

Seller is the interface describing actions to be performed on a seller inventory

func NewSellerFromInventory

func NewSellerFromInventory(inventory InventoryRecord, info ScraperInfo) Seller

func ReadSellerFromJSON

func ReadSellerFromJSON(r io.Reader) (Seller, error)

func Seller2Sellers

func Seller2Sellers(market Market) ([]Seller, error)

Separate a Market into multiple Seller objects

type Vendor

type Vendor interface {
	// Return the buylist for a Vendor. If not already loaded, it will start
	// scraping the vendor gathering the necessary data.
	Buylist() (BuylistRecord, error)

	// Return some information about the vendor
	Info() ScraperInfo
}

Vendor is the interface describing actions to be performed on a vendor buylist

func NewVendorFromBuylist

func NewVendorFromBuylist(buylist BuylistRecord, info ScraperInfo) Vendor

func ReadVendorFromJSON

func ReadVendorFromJSON(r io.Reader) (Vendor, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL