search

package
v0.0.0-...-83adff0 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2020 License: GPL-3.0 Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
const (
	GotoBangumi    = "bangumi"
	GotoAv         = "av"
	GotoWeb        = "web"
	GotoMovie      = "movie"
	GotoBangumiWeb = "bangumi_web"
	GotoSp         = "sp"
	GotoLive       = "live"
	GotoGame       = "game"
	GotoAuthor     = "author"
	GotoClip       = "clip"
	GotoAlbum      = "album"
	GotoArticle    = "article"
	GotoAudio      = "audio"
	GotoSpecial    = "special"
	GotoBanner     = "banner"
	GotoSpecialS   = "special_s"
	GotoConverge   = "converge"
	GotoPGC        = "pgc"
	GotoChannel    = "channel"
	GotoEP         = "ep"
	GotoTwitter    = "twitter"

	CoverIng      = "即将上映"
	CoverPay      = "付费观看"
	CoverFree     = "免费观看"
	CoverVipFree  = "付费观看"
	CoverVipOnly  = "专享"
	CoverVipFirst = "抢先"
)

default .

View Source
const (

	// AllLabel is the string that means all data
	AllLabel = "-1" // it means all for index
)

Variables

View Source
var (
	// AvHandler .
	AvHandler = func(a *v1.Arc) func(uri string) string {
		return func(uri string) string {
			if a == nil {
				return uri
			}
			if a.Dimension.Height != 0 || a.Dimension.Width != 0 {
				return fmt.Sprintf("%s?player_width=%d&player_height=%d&player_rotate=%d", uri, a.Dimension.Width, a.Dimension.Height, a.Dimension.Rotate)
			}
			return uri
		}
	}
)

Functions

func FillURI

func FillURI(gt, param string, f func(uri string) string) (uri string)

FillURI deal app schema .

func IdxSort

func IdxSort(sortV int) (sort string)

IdxSort treats the sort

func StatusMark

func StatusMark(status int) string

StatusMark cover status mark .

Types

type About

type About struct {
	ParamsCheck string `json:"params_check"`
	Total       string `json:"total"`
	MainHandler string `json:"main_handler"`
}

About def.

type AllForClient

type AllForClient struct {
	Pgc []*CommonResult `json:"tvpgc"`
	Ugc []*CommonResult `json:"tvugc"`
}

AllForClient def.

type AllResult

type AllResult struct {
	Pgc []*PgcResult `json:"tvpgc"`
	Ugc []*UgcResult `json:"tvugc"`
}

AllResult def .

type Bangumi

type Bangumi struct {
	Name          string `json:"name,omitempty"`
	SeasonID      int    `json:"season_id,omitempty"`
	Title         string `json:"title,omitempty"`
	Cover         string `json:"cover,omitempty"`
	Evaluate      string `json:"evaluate,omitempty"`
	NewestEpID    int    `json:"newest_ep_id,omitempty"`
	NewestEpIndex string `json:"newest_ep_index,omitempty"`
	IsFinish      int    `json:"is_finish,omitempty"`
	IsStarted     int    `json:"is_started,omitempty"`
	NewestCat     string `json:"newest_cat,omitempty"`
	NewestSeason  string `json:"newest_season,omitempty"`
	TotalCount    int    `json:"total_count,omitempty"`
	Pages         int    `json:"numPages,omitempty"`
	CatList       *struct {
		TV    int `json:"tv"`
		Movie int `json:"movie"`
		Ova   int `json:"ova"`
	} `json:"catlist,omitempty"`
}

Bangumi struct .

type Card

type Card struct {
	SeasonID    int64      `json:"season_id"`
	IsFollow    int        `json:"is_follow"`
	IsSelection int        `json:"is_selection"`
	Badge       string     `json:"badge"`
	BadgeType   int        `json:"badge_type"`
	Episodes    []*Episode `json:"episodes"`
}

Card for bangumi .

type CommonResult

type CommonResult struct {
	*PgcResult
	Type string `json:"type"`
}

CommonResult is the common result for both pgc & ugc .

type Cost

type Cost struct {
	About *About `json:"about"`
}

Cost def.

type Episode

type Episode struct {
	ID         int64  `json:"id"`
	Badge      string `json:"badge"`
	BadgeType  int    `json:"badge_type"`
	Status     int    `json:"status"`
	Cover      string `json:"cover"`
	Index      string `json:"index"`
	IndexTitle string `json:"index_title"`
}

Episode for bangumi card .

type EsCard

type EsCard struct {
	model.Card
	DataType int `json:"data_type"` // 1=pgc, 2=ugc
}

EsCard def.

func (*EsCard) FromPgc

func (v *EsCard) FromPgc(card *model.Card)

FromPgc def.

func (*EsCard) FromUgc

func (v *EsCard) FromUgc(card *model.Card)

FromUgc def.

type EsPage

type EsPage struct {
	Num     int `json:"num"`
	Size    int `json:"size"`
	Total   int `json:"total"`
	PageNum int `json:"page_num"`
}

EsPage def.

func (*EsPage) GetPageNb

func (v *EsPage) GetPageNb()

GetPageNb def.

type EsPager

type EsPager struct {
	Title  string    `json:"title"`
	Page   *EsPage   `json:"page"`
	Result []*EsCard `json:"result"`
}

EsPager def.

type EsPgcResult

type EsPgcResult struct {
	Page   *EsPage     `json:"page"`
	Result []*PgcEsMdl `json:"result"`
}

EsPgcResult def.

type EsUgcResult

type EsUgcResult struct {
	Page   *EsPage     `json:"page"`
	Result []*UgcEsMdl `json:"result"`
}

EsUgcResult def.

type IdxIntervSave

type IdxIntervSave struct {
	Pgc map[int][]int64
	Ugc map[int][]int64
}

IdxIntervSave def.

type Item

type Item struct {
	TrackID        string `json:"trackid,omitempty"`
	LinkType       string `json:"linktype,omitempty"`
	Position       int    `json:"position,omitempty"`
	SuggestKeyword string `json:"suggest_keyword,omitempty"`
	Title          string `json:"title,omitempty"`
	Name           string `json:"name,omitempty"`
	Cover          string `json:"cover,omitempty"`
	URI            string `json:"uri,omitempty"`
	Param          string `json:"param,omitempty"`
	Goto           string `json:"goto,omitempty"`
	// av
	Play     int        `json:"play,omitempty"`
	Danmaku  int        `json:"danmaku,omitempty"`
	Author   string     `json:"author,omitempty"`
	ViewType string     `json:"view_type,omitempty"`
	PTime    xtime.Time `json:"ptime,omitempty"`
	RecTags  []string   `json:"rec_tags,omitempty"`
	// media bangumi and mdeia ft
	Prompt   string  `json:"prompt,omitempty"`
	Episodes []*Item `json:"episodes,omitempty"`
	Label    string  `json:"label,omitempty"`
	// bangumi season
	Finish       int8    `json:"finish,omitempty"`
	Started      int8    `json:"started,omitempty"`
	Index        string  `json:"index,omitempty"`
	NewestCat    string  `json:"newest_cat,omitempty"`
	NewestSeason string  `json:"newest_season,omitempty"`
	CatDesc      string  `json:"cat_desc,omitempty"`
	TotalCount   int     `json:"total_count,omitempty"`
	MediaType    int     `json:"media_type,omitempty"`
	PlayState    int     `json:"play_state,omitempty"`
	Style        string  `json:"style,omitempty"`
	CV           string  `json:"cv,omitempty"`
	Rating       float64 `json:"rating,omitempty"`
	Vote         int     `json:"vote,omitempty"`
	RatingCount  int     `json:"rating_count,omitempty"`
	BadgeType    int     `json:"badge_type,omitempty"`
	// upper
	Sign           string          `json:"sign,omitempty"`
	Fans           int             `json:"fans,omitempty"`
	Level          int             `json:"level,omitempty"`
	Desc           string          `json:"desc,omitempty"`
	OfficialVerify *OfficialVerify `json:"official_verify,omitempty"`
	AvItems        []*Item         `json:"av_items,omitempty"`
	Item           []*Item         `json:"item,omitempty"`
	CTime          int64           `json:"ctime,omitempty"`
	IsUp           bool            `json:"is_up,omitempty"`
	LiveURI        string          `json:"live_uri,omitempty"`
	// movie
	ScreenDate string `json:"screen_date,omitempty"`
	Area       string `json:"area,omitempty"`
	CoverMark  string `json:"cover_mark,omitempty"`
	// user
	Face string `json:"face,omitempty"`
	// arc and sp
	Arcs int `json:"archives,omitempty"`
	// arc and movie
	Duration    string `json:"duration,omitempty"`
	DurationInt int64  `json:"duration_int,omitempty"`
	Actors      string `json:"actors,omitempty"`
	Staff       string `json:"staff,omitempty"`
	Length      int    `json:"length,omitempty"`
	Status      int    `json:"status,omitempty"`
}

Item struct .

func (*Item) FromMedia

func (i *Item) FromMedia(m *Media, prompt string, gt string, bangumis map[string]*Card)

FromMedia form func .

func (*Item) FromMovie

func (i *Item) FromMovie(m *Movie, as map[int64]*v1.Arc)

FromMovie form func .

func (*Item) FromSeason

func (i *Item) FromSeason(b *Bangumi, bangumi string)

FromSeason .

func (*Item) FromUpUser

func (i *Item) FromUpUser(u *User, as map[int64]*v1.Arc)

FromUpUser form func .

func (*Item) FromUser

func (i *Item) FromUser(u *User, as map[int64]*v1.Arc)

FromUser form func .

func (*Item) FromVideo

func (i *Item) FromVideo(v *Video, a *v1.Arc)

FromVideo form func .

type Media

type Media struct {
	MediaID    int64  `json:"media_id,omitempty"`
	SeasonID   int64  `json:"season_id,omitempty"`
	Title      string `json:"title,omitempty"`
	OrgTitle   string `json:"org_title,omitempty"`
	Styles     string `json:"styles,omitempty"`
	Cover      string `json:"cover,omitempty"`
	PlayState  int    `json:"play_state,omitempty"`
	MediaScore *struct {
		Score     float64 `json:"score,omitempty"`
		UserCount int     `json:"user_count,omitempty"`
	} `json:"media_score,omitempty"`
	MediaType  int        `json:"media_type,omitempty"`
	CV         string     `json:"cv,omitempty"`
	Staff      string     `json:"staff,omitempty"`
	Areas      string     `json:"areas,omitempty"`
	GotoURL    string     `json:"goto_url,omitempty"`
	Pubtime    xtime.Time `json:"pubtime,omitempty"`
	HitColumns []string   `json:"hit_columns,omitempty"`
}

Media struct .

type Movie

type Movie struct {
	Title      string `json:"title"`
	SpID       string `json:"spid"`
	Type       string `json:"type"`
	Aid        int64  `json:"aid"`
	Desc       string `json:"description"`
	Actors     string `json:"actors"`
	Staff      string `json:"staff"`
	Cover      string `json:"cover"`
	Pic        string `json:"pic"`
	ScreenDate string `json:"screenDate"`
	Area       string `json:"area"`
	Status     int    `json:"status"`
	Length     int    `json:"length"`
	Pages      int    `json:"numPages"`
}

Movie struct .

type NavInfo struct {
	Name  string `json:"name"`
	Total int    `json:"total"`
	Pages int    `json:"pages"`
	Type  int    `json:"type"`
	Show  int    `json:"show_more,omitempty"`
}

NavInfo struct .

type OfficialVerify

type OfficialVerify struct {
	Type int    `json:"type"`
	Desc string `json:"desc,omitempty"`
}

OfficialVerify struct .

type Page

type Page struct {
	NumResult int `json:"numResults"`
	Total     int `json:"total"`
	Pages     int `json:"pages"`
}

Page struct .

type PageCaches

type PageCaches struct {
	SaveCache string `json:"save cache"`
}

PageCaches def.

type PgcEsMdl

type PgcEsMdl struct {
	SeasonID int64 `json:"season_id"`
}

PgcEsMdl def.

type PgcResult

type PgcResult struct {
	*UgcResult
	CV         string             `json:"cv"`
	Staff      string             `json:"staff"`
	CornerMark *model.SnVipCorner `json:"cornermark"`
}

PgcResult def .

func (*PgcResult) ToCommon

func (p *PgcResult) ToCommon() (res *CommonResult)

ToCommon transform pgc to common .

type ReqEsPn

type ReqEsPn struct {
	Ps    int `form:"ps" default:"50"`
	Pn    int `form:"pn" default:"1"`
	Order int `form:"order" validate:"required"`
	Sort  int `form:"sort" default:"0"`
}

ReqEsPn is part of the es request for page related cfg

type ReqIdxInterv

type ReqIdxInterv struct {
	EsIDs    []int64
	Category int
	IsPGC    bool
	Pn       int
}

ReqIdxInterv is used for index intervention treatment

func (*ReqIdxInterv) FromPGC

func (v *ReqIdxInterv) FromPGC(sids []int64, req *ReqPgcIdx)

FromPGC def.

func (*ReqIdxInterv) FromUGC

func (v *ReqIdxInterv) FromUGC(aids []int64, req *ReqUgcIdx)

FromUGC def.

type ReqPgcIdx

type ReqPgcIdx struct {
	SeasonType    int    `form:"category" validate:"required,max=5"`
	ProducerID    int    `form:"producer_id"`
	Year          string `form:"year"`
	StyleID       int    `form:"style_id"`
	PubDate       string `form:"pub_date"`
	SeasonMonth   int    `form:"season_month" validate:"max=10"`
	SeasonStatus  []int  `form:"season_status,split"`
	Copyright     []int  `form:"copyright,split"`
	IsFinish      string `form:"is_finish"`
	Area          []int  `form:"area,split"`
	SeasonVersion int    `form:"season_version"`
	ReqEsPn
}

ReqPgcIdx is bm request for pgc index

func (*ReqPgcIdx) IsAll

func (v *ReqPgcIdx) IsAll(params []int) (res bool)

IsAll checks whether a slice of int means all data

func (*ReqPgcIdx) IsAllStr

func (v *ReqPgcIdx) IsAllStr(duration string) (res bool)

IsAllStr checks whether a string means all data

func (*ReqPgcIdx) IsDefault

func (v *ReqPgcIdx) IsDefault() bool

IsDefault def.

func (*ReqPgcIdx) PgcOrder

func (v *ReqPgcIdx) PgcOrder() (field string)

PgcOrder treats the order to get the responding field

func (*ReqPgcIdx) Title

func (v *ReqPgcIdx) Title() string

Title def.

type ReqSearch

type ReqSearch struct {
	SearchType string `form:"search_type" validate:"required"`
	Order      string `form:"order"`
	Category   int    `form:"category"`
	Platform   string `form:"platform"  validate:"required"`
	Build      string `form:"build"  validate:"required"`
	MobiAPP    string `form:"mobi_app"`
	Device     string `form:"device"`
	Keyword    string `form:"keyword"  validate:"required"`
	Page       int    `form:"page"  validate:"required,min=1"`
	Pagesize   int    `form:"pagesize"`
}

ReqSearch def .

type ReqSug

type ReqSug struct {
	MobiApp  string `form:"mobi_app"`
	Build    string `form:"build"`
	Platform string `form:"platform"`
	Term     string `form:"term" validate:"required"`
}

ReqSug def.

type ReqUgcIdx

type ReqUgcIdx struct {
	ParentTID int32  `form:"category" validate:"required"`
	SecondTID int32  `form:"typeid"`
	PubTime   string `form:"pubtime"`
	ReqEsPn
}

ReqUgcIdx is bm request for ugc index

func (*ReqUgcIdx) IsDefault

func (v *ReqUgcIdx) IsDefault() bool

IsDefault def.

func (*ReqUgcIdx) TimeStr

func (v *ReqUgcIdx) TimeStr() (res *UgcTime, err error)

TimeStr picks json str from request and returns the time range struct in String format

type RespAll

type RespAll struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	*ResultResponse
	PageInfo *pageinfo  `json:"pageinfo"`
	Result   *AllResult `json:"result"`
}

RespAll def .

type RespForClient

type RespForClient struct {
	*ResultResponse
	SearchType string          `json:"search_type"`
	PageInfo   *pageinfo       `json:"pageinfo"`
	ResultAll  *AllForClient   `json:"resultall"`
	PGC        []*CommonResult `json:"pgc"`
	UGC        []*CommonResult `json:"ugc"`
}

RespForClient def.

type RespPgc

type RespPgc struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	*ResultResponse
	Result []*PgcResult `json:"result"`
}

RespPgc def .

type RespUgc

type RespUgc struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	*ResultResponse
	Result []*UgcResult `json:"result"`
}

RespUgc def .

type Result

type Result struct {
	Tag []*STag `json:"tag"`
}

Result def.

type ResultAll

type ResultAll struct {
	Trackid   string      `json:"trackid,omitempty"`
	Page      int         `json:"page,omitempty"`
	NavInfo   []*NavInfo  `json:"nav,omitempty"`
	Items     ResultItems `json:"items,omitempty"`
	Item      []*Item     `json:"item,omitempty"` // 混排的数据(未用到)
	Attribute int32       `json:"attribute"`      // 实验中开关
}

ResultAll struct .

type ResultItems

type ResultItems struct {
	Season2 []*Item `json:"season2,omitempty"`
	Season  []*Item `json:"season,omitempty"` // 老数据字段(未用到)
	Upper   []*Item `json:"upper,omitempty"`
	Movie2  []*Item `json:"movie2,omitempty"`
	Movie   []*Item `json:"movie,omitempty"` // 老数据字段(未用到)
	Archive []*Item `json:"archive,omitempty"`
}

ResultItems struct .

type ResultResponse

type ResultResponse struct {
	Page       int    `json:"page"`
	Pagesize   int    `json:"pagesize"`
	NumResults int    `json:"numResults"`
	NumPages   int    `json:"numPages"`
	Seid       string `json:"seid"`
}

ResultResponse def .

type STag

type STag struct {
	Value string `json:"value"`
	Ref   int    `json:"ref"`
	Name  string `json:"name"`
	Spid  int    `json:"spid"`
	Type  string `json:"type"`
}

STag def.

type Search struct {
	Code           int    `json:"code,omitempty"`
	Trackid        string `json:"seid,omitempty"`
	Page           int    `json:"page,omitempty"`
	PageSize       int    `json:"pagesize,omitempty"`
	Total          int    `json:"total,omitempty"`
	NumResults     int    `json:"numResults,omitempty"`
	NumPages       int    `json:"numPages,omitempty"`
	SuggestKeyword string `json:"suggest_keyword,omitempty"`
	Attribute      int32  `json:"exp_bits,omitempty"`
	PageInfo       struct {
		Bangumi      *Page `json:"bangumi,omitempty"`
		UpUser       *Page `json:"upuser,omitempty"`
		BiliUser     *Page `json:"bili_user,omitempty"`
		User         *Page `json:"user,omitempty"`
		Movie        *Page `json:"movie,omitempty"`
		Film         *Page `json:"pgc,omitempty"`
		MediaBangumi *Page `json:"media_bangumi,omitempty"`
		MediaFt      *Page `json:"media_ft,omitempty"`
	} `json:"pageinfo,omitempty"`
	Result struct {
		Bangumi      []*Bangumi `json:"bangumi,omitempty"`
		UpUser       []*User    `json:"upuser,omitempty"`
		BiliUser     []*User    `json:"bili_user,omitempty"`
		User         []*User    `json:"user,omitempty"`
		Movie        []*Movie   `json:"movie,omitempty"`
		Video        []*Video   `json:"video,omitempty"`
		MediaBangumi []*Media   `json:"media_bangumi,omitempty"`
		MediaFt      []*Media   `json:"media_ft,omitempty"`
	} `json:"result,omitempty"`
}

Search all .

type Sengine

type Sengine struct {
	Usage int `json:"usage"`
}

Sengine def.

type SrvUgcIdx

type SrvUgcIdx struct {
	TIDs    []int32
	PubTime *UgcTime
	ReqEsPn
}

SrvUgcIdx is the request treated by service for DAO, like type_id field and pub_time

func (*SrvUgcIdx) UgcOrder

func (v *SrvUgcIdx) UgcOrder() (field string)

UgcOrder treats the order to get the responding field

type SugResponse

type SugResponse struct {
	Code       int         `json:"code"`
	Cost       *Cost       `json:"cost"`
	Result     *Result     `json:"result"`
	PageCaches *PageCaches `json:"page caches"`
	Sengine    *Sengine    `json:"sengine"`
	Stoken     string      `json:"stoken"`
}

SugResponse is the structure of search api response

type TypeSearch

type TypeSearch struct {
	TrackID string  `json:"trackid"`
	Pages   int     `json:"pages"`
	Total   int     `json:"total"`
	Items   []*Item `json:"items,omitempty"`
}

TypeSearch struct .

type UgcEsMdl

type UgcEsMdl struct {
	AID    int64 `json:"aid"`
	TypeID int32 `json:"typeid"`
}

UgcEsMdl def.

type UgcResult

type UgcResult struct {
	ID          int    `json:"id"`
	Title       string `json:"title"`
	Cover       string `json:"cover"`
	Description string `json:"description"`
	Pubtime     int    `json:"pubtime"`
	Category    int    `json:"category"`
}

UgcResult def .

func (*UgcResult) ToCommon

func (p *UgcResult) ToCommon() (res *CommonResult)

ToCommon transform pgc to common .

type UgcTime

type UgcTime struct {
	STime string `json:"stime"`
	ETime string `json:"etime"`
}

UgcTime def. STRING for ES

type UgcTimeV

type UgcTimeV struct {
	STime time.Time `json:"stime"`
	ETime time.Time `json:"etime"`
}

UgcTimeV def. INT64 for http

type User

type User struct {
	Type       string `json:"type"`
	Mid        int64  `json:"mid,omitempty"`
	Name       string `json:"uname,omitempty"`
	Usign      string `json:"usign,omitempty"`
	Fans       int    `json:"fans,omitempty"`
	Videos     int    `json:"videos,omitempty"`
	Pic        string `json:"upic,omitempty"`
	VerifyInfo string `json:"verify_info"`
	Level      int    `json:"level,omitempty"`
	Gender     int    `json:"gender"`
	IsUpuser   int    `json:"is_upuser,omitempty"`
	IsLive     int    `json:"is_live,omitempty"`
	RoomID     int64  `json:"room_id,omitempty"`
	Res        []*struct {
		Aid      int64       `json:"aid,omitempty"`
		Title    string      `json:"title,omitempty"`
		Pubdate  int64       `json:"pubdate,omitempty"`
		ArcURL   string      `json:"arcurl,omitempty"`
		Pic      string      `json:"pic,omitempty"`
		Play     interface{} `json:"play,omitempty"`
		Danmaku  int         `json:"dm,omitempty"`
		Coin     int         `json:"coin"`
		Fav      int         `json:"fav"`
		Desc     string      `json:"desc"`
		Duration string      `json:"duration,omitempty"`
	} `json:"res,omitempty"`
	OfficialVerify *OfficialVerify `json:"official_verify,omitempty"`
	*ResultResponse
}

User struct res .

type UserSearch

type UserSearch struct {
	SearchType string `form:"search_type" validate:"required"`
	Order      string `form:"order"`
	Category   int    `form:"category"`
	Platform   string `form:"platform"`
	Build      string `form:"build"`
	MobiAPP    string `form:"mobi_app"`
	Device     string `form:"device"`
	Keyword    string `form:"keyword"  validate:"required"`
	Page       int    `form:"page"  validate:"required,min=1"`
	Pagesize   int    `form:"pagesize"`
	UserType   int    `form:"user_type"`
	Highlight  int    `form:"highlight"`
	OrderSort  int    `form:"order_sort"`
	FromSource string `form:"from_source"`
	Buvid      string `form:"buvid"`
	Duration   int    `form:"duration"` // 视频时长
	// 传递参数,给到dao用
	SeasonNum int   `form:"season_num"`
	MovieNum  int   `form:"movie_num"`
	RID       int   `form:"rid"`
	MID       int64 `form:"mid"`
}

UserSearch user search request .

type Video

type Video struct {
	ID       int64       `json:"id"`
	Author   string      `json:"author"`
	Title    string      `json:"title"`
	Pic      string      `json:"pic"`
	Desc     string      `json:"description"`
	Play     interface{} `json:"play"`
	Danmaku  int         `json:"video_review"`
	Duration string      `json:"duration"`
	Pages    int         `json:"numPages"`
	ViewType string      `json:"view_type"`
	RecTags  []string    `json:"rec_tags"`
}

Video struct .

Jump to

Keyboard shortcuts

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