tcgplayer

package
v0.4.44 Latest Latest
Warning

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

Go to latest
Published: Aug 13, 2024 License: MIT Imports: 22 Imported by: 2

Documentation

Index

Constants

View Source
const (
	CategoryMagic   = 1
	CategoryYuGiOh  = 2
	CategoryPokemon = 3
	CategoryLorcana = 71

	ProductTypeCards               = "Cards"
	ProductTypeBoosterBox          = "Booster Box"
	ProductTypeBoosterPack         = "Booster Pack"
	ProductTypeSealedProducts      = "Sealed Products"
	ProductTypeIntroPack           = "Intro Pack"
	ProductTypeFatPack             = "Fat Pack"
	ProductTypeBoxSets             = "Box Sets"
	ProductTypePreconEventDecks    = "Precon/Event Decks"
	ProductTypeMagicDeckPack       = "Magic Deck Pack"
	ProductTypeMagicBoosterBoxCase = "Magic Booster Box Case"
	ProductTypeAll5IntroPacks      = "All 5 Intro Packs"
	ProductTypeIntroPackDisplay    = "Intro Pack Display"
	ProductType3xMagicBoosterPacks = "3x Magic Booster Packs"
	ProductTypeBoosterBattlePack   = "Booster Battle Pack"

	MaxLimit = 100
)
View Source
const (
	SellersPageURL     = "https://shop.tcgplayer.com/sellers"
	SellerInventoryURL = "https://mp-search-api.tcgplayer.com/v1/search/request?q=&isList=true&mpfev=1953"
	SellerListingURL   = "https://mp-search-api.tcgplayer.com/v1/product/%d/listings"

	DefaultSellerRequestSize = 50

	MaxGlobalScrapingValue = 8000
)
View Source
const (
	BaseProductURL    = "https://www.tcgplayer.com/product/"
	PartnerProductURL = "https://tcgplayer.pxf.io/c/%s/1830156/21018"
)
View Source
const (
	BANAPIURL = "https://www.mtgban.com/api/mtgban/all.json?cond=true&vendor=TCG+Direct&sig="
)
View Source
const (
	SYPCSVURL = "https://store.tcgplayer.com/admin/direct/ExportSYPList?categoryid=1&setNameId=All&conditionId=All"
)
View Source
const TCGBuylistOffersURL = "https://store.tcgplayer.com/buylist/viewtopsellerprices?productConditionId="
View Source
const TCGBuylistUpdateQtyURL = "https://store.tcgplayer.com/buylist/updatequantity"
View Source
const TCGCreateCartURL = "https://mpgateway.tcgplayer.com/v1/cart/create/usercart"
View Source
const TCGUserDataURL = "https://mpapi.tcgplayer.com/v2/user?isGuest=false"

Variables

View Source
var SKUConditionMap = map[int]string{
	1: "NM",
	2: "SP",
	3: "MP",
	4: "HP",
	5: "PO",
}

Functions

func DirectPriceAfterFees added in v0.4.34

func DirectPriceAfterFees(price float64) float64

func LoadTCGSKUs

func LoadTCGSKUs(reader io.Reader) (mtgjson.AllTCGSkus, error)

func Preprocess

func Preprocess(product *TCGProduct, editions map[int]string) (*mtgmatcher.InputCard, error)

func SellerKeyExists added in v0.4.22

func SellerKeyExists(sellerKey string) bool

func SellerName2ID added in v0.3.16

func SellerName2ID(sellerName string) (string, error)

func TCGCreateCartKey added in v0.4.25

func TCGCreateCartKey(userId string) (string, error)

func TCGLatestSales

func TCGLatestSales(tcgProductId string, foil ...bool) (*latestSalesResponse, error)

func TCGPlayerProductURL

func TCGPlayerProductURL(productId int, printing, affiliate, condition, language string, isDirect bool) string

Types

type BANPriceResponse added in v0.4.34

type BANPriceResponse struct {
	Error string `json:"error,omitempty"`
	Meta  struct {
		Date    time.Time `json:"date"`
		Version string    `json:"version"`
		BaseURL string    `json:"base_url"`
	} `json:"meta"`

	// uuid > store > price {regular/foil/etched}
	Retail map[string]map[string]BanPrice `json:"retail,omitempty"`
}

type BanPrice added in v0.4.34

type BanPrice struct {
	Conditions map[string]float64 `json:"conditions"`
}

type CookieClient added in v0.4.37

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

func NewCookieClient added in v0.4.37

func NewCookieClient(authKey string) *CookieClient

func (*CookieClient) BuylistSetQuantity added in v0.4.37

func (tcg *CookieClient) BuylistSetQuantity(skuId, qty int) (string, error)

func (*CookieClient) BuylistViewOffers added in v0.4.37

func (tcg *CookieClient) BuylistViewOffers(skuId int) ([]TCGBuylistOffer, error)

func (*CookieClient) GetUserData added in v0.4.37

func (tcg *CookieClient) GetUserData() (*TCGUserData, error)

type LatestSalesData

type LatestSalesData struct {
	Condition       string    `json:"condition"`
	Variant         string    `json:"variant"`
	Language        string    `json:"language"`
	Quantity        int       `json:"quantity"`
	Title           string    `json:"title"`
	ListingType     string    `json:"listingType"`
	CustomListingID string    `json:"customListingId"`
	PurchasePrice   float64   `json:"purchasePrice"`
	ShippingPrice   float64   `json:"shippingPrice"`
	OrderDate       time.Time `json:"orderDate"`
}

type ListingData added in v0.4.38

type ListingData struct {
	ProductId       int     `json:"product_id"`
	SkuId           int     `json:"sku_id"`
	Quantity        int     `json:"quantity"`
	SellerKey       string  `json:"seller_key"`
	Price           float64 `json:"price"`
	DirectInventory int     `json:"direct_inventory"`
	ConditionFull   string  `json:"condition_full"`
	Condition       string  `json:"condition"`
	Printing        string  `json:"printing"`
	Foil            bool    `json:"foil"`
}

func GetDirectQtysForProductId added in v0.4.38

func GetDirectQtysForProductId(productId int, onlyDirect bool) []ListingData

type SellerInventoryResult added in v0.3.16

type SellerInventoryResult struct {
	FoilOnly                bool    `json:"foilOnly"`
	ImageCount              float64 `json:"imageCount"`
	LowestPrice             float64 `json:"lowestPrice"`
	LowestPriceWithShipping float64 `json:"lowestPriceWithShipping"`
	MarketPrice             float64 `json:"marketPrice"`
	MaxFulfillableQuantity  float64 `json:"maxFulfillableQuantity"`
	NormalOnly              bool    `json:"normalOnly"`
	ProductID               float64 `json:"productId"`
	ProductLineID           float64 `json:"productLineId"`
	ProductLineName         string  `json:"productLineName"`
	ProductLineURLName      string  `json:"productLineUrlName"`
	ProductName             string  `json:"productName"`
	ProductStatusID         float64 `json:"productStatusId"`
	ProductTypeID           float64 `json:"productTypeId"`
	ProductTypeName         string  `json:"productTypeName"`
	ProductURLName          string  `json:"productUrlName"`
	RarityName              string  `json:"rarityName"`
	Score                   float64 `json:"score"`
	Sealed                  bool    `json:"sealed"`
	SellerListable          bool    `json:"sellerListable"`
	Sellers                 float64 `json:"sellers"`
	SetCode                 string  `json:"setCode"`
	SetID                   float64 `json:"setId"`
	SetName                 string  `json:"setName"`
	SetURLName              string  `json:"setUrlName"`
	ShippingCategoryID      float64 `json:"shippingCategoryId"`
	TotalListings           float64 `json:"totalListings"`
	CustomAttributes        struct {
		Number string `json:"number"`
	} `json:"customAttributes"`
	Listings []SellerListing `json:"listings"`
}

type SellerListing added in v0.4.21

type SellerListing struct {
	ChannelID            float64 `json:"channelId"`
	Condition            string  `json:"condition"`
	ConditionID          float64 `json:"conditionId"`
	DirectInventory      float64 `json:"directInventory"`
	DirectProduct        bool    `json:"directProduct"`
	DirectSeller         bool    `json:"directSeller"`
	ForwardFreight       bool    `json:"forwardFreight"`
	GoldSeller           bool    `json:"goldSeller"`
	Language             string  `json:"language"`
	LanguageAbbreviation string  `json:"languageAbbreviation"`
	LanguageID           float64 `json:"languageId"`
	ListingID            float64 `json:"listingId"`
	ListingType          string  `json:"listingType"`
	Price                float64 `json:"price"`
	Printing             string  `json:"printing"`
	ProductConditionID   float64 `json:"productConditionId"`
	ProductID            float64 `json:"productId"`
	Quantity             float64 `json:"quantity"`
	RankedShippingPrice  float64 `json:"rankedShippingPrice"`
	Score                float64 `json:"score"`
	SellerID             string  `json:"sellerId"`
	SellerKey            string  `json:"sellerKey"`
	SellerName           string  `json:"sellerName"`
	SellerRating         float64 `json:"sellerRating"`
	SellerSales          string  `json:"sellerSales"`
	SellerShippingPrice  float64 `json:"sellerShippingPrice"`
	ShippingPrice        float64 `json:"shippingPrice"`
	VerifiedSeller       bool    `json:"verifiedSeller"`
}

type TCGAutoClient added in v0.3.34

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

func NewTCGAutoClient added in v0.3.34

func NewTCGAutoClient(cartId string) *TCGAutoClient

func (*TCGAutoClient) AddProductToCart added in v0.3.34

func (tcg *TCGAutoClient) AddProductToCart(sellerKey string, skuId, qty int, isDirect bool) (*TCGAutocartResponse, error)

type TCGAutocartRequest added in v0.3.34

type TCGAutocartRequest struct {
	SKU               int    `json:"sku"`
	SellerKey         string `json:"sellerKey"`
	ChannelID         int    `json:"channelId"`
	RequestedQuantity int    `json:"requestedQuantity"`
	Price             int    `json:"price"`
	IsDirect          bool   `json:"isDirect"`
}

type TCGAutocartResponse added in v0.3.34

type TCGAutocartResponse struct {
	Errors []struct {
		Code    string `json:"code"`
		Message string `json:"message"`
	} `json:"errors"`
	Results []struct {
		IsDirect                bool    `json:"isDirect"`
		SellerQuantityAvailable int     `json:"sellerQuantityAvailable"`
		ItemQuantityInCart      int     `json:"itemQuantityInCart"`
		CurrentPrice            float64 `json:"currentPrice"`
		Status                  int     `json:"status"`
	}
}

type TCGBuylistOffer added in v0.4.36

type TCGBuylistOffer struct {
	SkuId      int
	SellerName string
	Price      float64
	Quantity   int
}

type TCGCategory

type TCGCategory struct {
	CategoryID        int    `json:"categoryId"`
	Name              string `json:"name"`
	ModifiedOn        string `json:"modifiedOn"`
	DisplayName       string `json:"displayName"`
	SeoCategoryName   string `json:"seoCategoryName"`
	SealedLabel       string `json:"sealedLabel"`
	NonSealedLabel    string `json:"nonSealedLabel"`
	ConditionGuideURL string `json:"conditionGuideUrl"`
	IsScannable       bool   `json:"isScannable"`
	Popularity        int    `json:"popularity"`
}

type TCGClient

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

func NewTCGClient

func NewTCGClient(publicId, privateId string) *TCGClient

func NewTCGSellerClient added in v0.3.42

func NewTCGSellerClient() *TCGClient

func (*TCGClient) EditionMap

func (tcg *TCGClient) EditionMap(category int) (map[int]TCGGroup, error)

func (*TCGClient) Get

func (tcg *TCGClient) Get(url string) (*TCGResponse, error)

Perform an authenticated GET request on any URL

func (*TCGClient) ListAllGroups

func (tcg *TCGClient) ListAllGroups(category int, offset int, limit int) ([]TCGGroup, error)

func (*TCGClient) ListAllProducts

func (tcg *TCGClient) ListAllProducts(category int, productTypes []string, includeSkus bool, offset int, limit int) ([]TCGProduct, error)

func (*TCGClient) ListCategoryPrintings added in v0.4.42

func (tcg *TCGClient) ListCategoryPrintings(category int) ([]TCGPrinting, error)

func (*TCGClient) ListProducts added in v0.4.42

func (tcg *TCGClient) ListProducts(productIds []int, includeSkus bool) ([]TCGProduct, error)

func (*TCGClient) SKUsForId

func (tcg *TCGClient) SKUsForId(productId string) ([]TCGSKU, error)

func (*TCGClient) TCGBuylistPricesForSKUs

func (tcg *TCGClient) TCGBuylistPricesForSKUs(ids []string) ([]TCGSKUPrice, error)

func (*TCGClient) TCGCategoriesDetails

func (tcg *TCGClient) TCGCategoriesDetails(ids []int) ([]TCGCategory, error)

func (*TCGClient) TCGInventoryForSeller added in v0.3.42

func (tcg *TCGClient) TCGInventoryForSeller(sellerKeys []string, size, page int, useDirect bool, finishes []string, sets ...string) (*sellerInventoryResponse, error)

func (*TCGClient) TCGInventoryListing added in v0.4.21

func (tcg *TCGClient) TCGInventoryListing(productId, size, page int, useDirect bool) ([]SellerListing, error)

func (*TCGClient) TCGPricesForIds

func (tcg *TCGClient) TCGPricesForIds(productIds []string) ([]TCGPrice, error)

func (*TCGClient) TCGPricesForSKUs

func (tcg *TCGClient) TCGPricesForSKUs(ids []string) ([]TCGSKUPrice, error)

func (*TCGClient) TotalGroups

func (tcg *TCGClient) TotalGroups(category int) (int, error)

func (*TCGClient) TotalProducts

func (tcg *TCGClient) TotalProducts(category int, productTypes []string) (int, error)

type TCGDirectNet

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

func NewTCGDirectNet

func NewTCGDirectNet(signature string) *TCGDirectNet

func (*TCGDirectNet) Buylist

func (tcg *TCGDirectNet) Buylist() (mtgban.BuylistRecord, error)

func (*TCGDirectNet) Info

func (tcg *TCGDirectNet) Info() (info mtgban.ScraperInfo)

type TCGGroup

type TCGGroup struct {
	GroupID      int    `json:"groupId"`
	Name         string `json:"name"`
	Abbreviation string `json:"abbreviation"`
	Supplemental bool   `json:"supplemental"`
	PublishedOn  string `json:"publishedOn"`
	ModifiedOn   string `json:"modifiedOn"`
	CategoryID   int    `json:"categoryId"`
}

type TCGLorcana added in v0.4.42

type TCGLorcana struct {
	LogCallback mtgban.LogCallbackFunc

	Affiliate      string
	MaxConcurrency int
	// contains filtered or unexported fields
}

func NewLorcanaScraper added in v0.4.42

func NewLorcanaScraper(publicId, privateId string) (*TCGLorcana, error)

func (*TCGLorcana) Info added in v0.4.42

func (tcg *TCGLorcana) Info() (info mtgban.ScraperInfo)

func (*TCGLorcana) Inventory added in v0.4.42

func (tcg *TCGLorcana) Inventory() (mtgban.InventoryRecord, error)

type TCGLorcanaIndex added in v0.4.42

type TCGLorcanaIndex struct {
	LogCallback mtgban.LogCallbackFunc

	Affiliate      string
	MaxConcurrency int
	// contains filtered or unexported fields
}

func NewLorcanaIndex added in v0.4.42

func NewLorcanaIndex(publicId, privateId string) (*TCGLorcanaIndex, error)

func (*TCGLorcanaIndex) Info added in v0.4.42

func (tcg *TCGLorcanaIndex) Info() (info mtgban.ScraperInfo)

func (*TCGLorcanaIndex) Inventory added in v0.4.42

func (tcg *TCGLorcanaIndex) Inventory() (mtgban.InventoryRecord, error)

func (*TCGLorcanaIndex) MarketNames added in v0.4.42

func (tcg *TCGLorcanaIndex) MarketNames() []string

type TCGPlayerGeneric

type TCGPlayerGeneric struct {
	LogCallback mtgban.LogCallbackFunc

	Affiliate      string
	MaxConcurrency int
	// contains filtered or unexported fields
}

func NewScraperGeneric

func NewScraperGeneric(publicId, privateId string, category int, groups ...string) (*TCGPlayerGeneric, error)

func (*TCGPlayerGeneric) Info

func (tcg *TCGPlayerGeneric) Info() (info mtgban.ScraperInfo)

func (*TCGPlayerGeneric) Inventory

func (tcg *TCGPlayerGeneric) Inventory() (mtgban.InventoryRecord, error)

type TCGPlayerIndex

type TCGPlayerIndex struct {
	LogCallback mtgban.LogCallbackFunc

	Affiliate      string
	MaxConcurrency int
	// contains filtered or unexported fields
}

func NewScraperIndex

func NewScraperIndex(publicId, privateId string) *TCGPlayerIndex

func (*TCGPlayerIndex) Info

func (tcg *TCGPlayerIndex) Info() (info mtgban.ScraperInfo)

func (*TCGPlayerIndex) Inventory

func (tcg *TCGPlayerIndex) Inventory() (mtgban.InventoryRecord, error)

func (*TCGPlayerIndex) MarketNames

func (tcg *TCGPlayerIndex) MarketNames() []string

type TCGPlayerMarket

type TCGPlayerMarket struct {
	LogCallback mtgban.LogCallbackFunc

	Affiliate      string
	MaxConcurrency int

	// The cache data defining SKU data, if not set it will be loaded
	// from the default location on mtgjson website.
	SKUsData map[string][]mtgjson.TCGSku
	// contains filtered or unexported fields
}

func NewScraperMarket

func NewScraperMarket(publicId, privateId string) *TCGPlayerMarket

func (*TCGPlayerMarket) Buylist

func (tcg *TCGPlayerMarket) Buylist() (mtgban.BuylistRecord, error)

func (*TCGPlayerMarket) Info

func (tcg *TCGPlayerMarket) Info() (info mtgban.ScraperInfo)

func (*TCGPlayerMarket) Inventory

func (tcg *TCGPlayerMarket) Inventory() (mtgban.InventoryRecord, error)

func (*TCGPlayerMarket) MarketNames

func (tcg *TCGPlayerMarket) MarketNames() []string

type TCGPlayerSealed

type TCGPlayerSealed struct {
	LogCallback    mtgban.LogCallbackFunc
	Affiliate      string
	MaxConcurrency int

	SKUsData map[string][]mtgjson.TCGSku
	// contains filtered or unexported fields
}

func NewScraperSealed

func NewScraperSealed(publicId, privateId string) *TCGPlayerSealed

func (*TCGPlayerSealed) Info

func (tcg *TCGPlayerSealed) Info() (info mtgban.ScraperInfo)

func (*TCGPlayerSealed) Inventory

func (tcg *TCGPlayerSealed) Inventory() (mtgban.InventoryRecord, error)

type TCGPrice

type TCGPrice struct {
	ProductId      int     `json:"productId"`
	LowPrice       float64 `json:"lowPrice"`
	MarketPrice    float64 `json:"marketPrice"`
	MidPrice       float64 `json:"midPrice"`
	DirectLowPrice float64 `json:"directLowPrice"`
	SubTypeName    string  `json:"subTypeName"`
}

type TCGPrinting added in v0.4.42

type TCGPrinting struct {
	PrintingId int    `json:"printingId"`
	Name       string `json:"name"`
}

type TCGProduct

type TCGProduct struct {
	ProductId  int      `json:"productId"`
	Name       string   `json:"name"`
	CleanName  string   `json:"cleanName"`
	ImageUrl   string   `json:"imageUrl"`
	GroupId    int      `json:"groupId"`
	URL        string   `json:"url"`
	ModifiedOn string   `json:"modifiedOn"`
	Skus       []TCGSKU `json:"skus,omitempty"`

	// Only available for catalog/products API calls
	ExtendedData []struct {
		Name        string `json:"name"`
		DisplayName string `json:"displayName"`
		Value       string `json:"value"`
	} `json:"extendedData,omitempty"`
}

func (*TCGProduct) GetNameAndVariant added in v0.3.33

func (tcgp *TCGProduct) GetNameAndVariant() (string, string)

func (*TCGProduct) GetNumber added in v0.3.33

func (tcgp *TCGProduct) GetNumber() string

func (*TCGProduct) IsToken added in v0.3.33

func (tcgp *TCGProduct) IsToken() bool

type TCGResponse

type TCGResponse struct {
	TotalItems int             `json:"totalItems"`
	Success    bool            `json:"success"`
	Errors     []string        `json:"errors"`
	Results    json.RawMessage `json:"results"`
}

type TCGSKU

type TCGSKU struct {
	SkuId       int `json:"skuId"`
	ProductId   int `json:"productId"`
	LanguageId  int `json:"languageId"`
	PrintingId  int `json:"printingId"`
	ConditionId int `json:"conditionId"`
}

type TCGSKUPrice

type TCGSKUPrice struct {
	SkuId int `json:"skuId"`

	// Only availabe from TCGPricesForSKUs()
	LowPrice           float64 `json:"lowPrice"`
	LowestShipping     float64 `json:"lowestShipping"`
	LowestListingPrice float64 `json:"lowestListingPrice"`
	MarketPrice        float64 `json:"marketPrice"`
	DirectLowPrice     float64 `json:"directLowPrice"`

	// Only available from TCGBuylistPricesForSKUs()
	BuylistPrices struct {
		High   float64 `json:"high"`
		Market float64 `json:"market"`
	} `json:"prices"`
}

type TCGSYP added in v0.4.30

type TCGSYP struct {
	SkuId       int
	MarketPrice float64
	MaxQty      int
}

func LoadSyp added in v0.4.30

func LoadSyp(auth string) ([]TCGSYP, error)

type TCGSYPList

type TCGSYPList struct {
	LogCallback mtgban.LogCallbackFunc
	Affiliate   string
	// contains filtered or unexported fields
}

func NewScraperSYP

func NewScraperSYP(auth string) *TCGSYPList

func (*TCGSYPList) Buylist added in v0.4.33

func (tcg *TCGSYPList) Buylist() (mtgban.BuylistRecord, error)

func (*TCGSYPList) Info

func (tcg *TCGSYPList) Info() (info mtgban.ScraperInfo)

type TCGSellerInventory added in v0.3.16

type TCGSellerInventory struct {
	LogCallback    mtgban.LogCallbackFunc
	MaxConcurrency int
	Affiliate      string
	// contains filtered or unexported fields
}

func NewScraperForSeller added in v0.3.16

func NewScraperForSeller(sellerName string, onlyDirect bool) (*TCGSellerInventory, error)

func NewScraperForSellerIds added in v0.3.42

func NewScraperForSellerIds(sellerKeys []string, onlyDirect bool) *TCGSellerInventory

func (*TCGSellerInventory) Info added in v0.3.16

func (tcg *TCGSellerInventory) Info() (info mtgban.ScraperInfo)

func (*TCGSellerInventory) Inventory added in v0.3.16

func (tcg *TCGSellerInventory) Inventory() (mtgban.InventoryRecord, error)

type TCGUserData added in v0.4.25

type TCGUserData struct {
	UserName                string `json:"userName"`
	UserID                  int    `json:"userId"`
	UserKey                 string `json:"userKey"`
	IsSubscriber            bool   `json:"isSubscriber"`
	LastUsedShippingAddress struct {
		FirstName string `json:"firstName"`
		LastName  string `json:"lastName"`
		Address1  string `json:"address1"`
		Address2  string `json:"address2"`
		City      string `json:"city"`
		State     string `json:"state"`
		Zipcode   string `json:"zipcode"`
		Country   string `json:"country"`
		Phone     string `json:"phone"`
	} `json:"lastUsedShippingAddress"`
	ShippingCountry     string `json:"shippingCountry"`
	CreatedAt           string `json:"createdAt"`
	ExternalUserID      string `json:"externalUserId"`
	IsGuest             any    `json:"isGuest"`
	IsValidated         bool   `json:"isValidated"`
	CartKey             string `json:"cartKey"`
	SaveForLaterKey     string `json:"saveForLaterKey"`
	ProductLineAffinity any    `json:"productLineAffinity"`
	Traits              struct {
		ProductLineAffinityMostViewed any `json:"product_line_affinity_most_viewed"`
		Apv                           int `json:"apv"`
	} `json:"traits"`
	SellerKeys []string `json:"sellerKeys"`
}

type TCGUserResponse added in v0.4.25

type TCGUserResponse struct {
	Errors []struct {
		Code    string `json:"code"`
		Message string `json:"message"`
	} `json:"errors"`
	Results []TCGUserData `json:"results"`
}

Jump to

Keyboard shortcuts

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