telegram

package
v0.5.1 Latest Latest
Warning

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

Go to latest
Published: Nov 28, 2022 License: MIT Imports: 63 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// MainMenuCommandWebApp  = "⤵️ Recv"
	// MainMenuCommandBalance = "Balance"
	// MainMenuCommandInvoice = "⚡️ Invoice"
	// MainMenuCommandHelp    = "📖 Help"
	// MainMenuCommandSend    = "⤴️ Send"
	// SendMenuCommandEnter   = "👤 Enter"
	MainMenuCommandWebApp  = "⤵️"
	MainMenuCommandBalance = "Balance"
	MainMenuCommandInvoice = "⚡️ Invoice"
	MainMenuCommandHelp    = "📖 Help"
	MainMenuCommandSend    = "⤴️"
	SendMenuCommandEnter   = "👤 Enter"
)

we can't use space in the label of buttons, because string splitting will mess everything up.

View Source
const (
	MessageOrderedByReplyToFrom = "message.reply_to_message.from.id"
	TipTooltipKeyPattern        = "tip-tool-tip:*"
)
View Source
const (
	InvoiceCallbackGeneric = iota + 1
	InvoiceCallbackInlineReceive
	InvoiceCallbackLNURLPayReceive
	InvoiceCallbackGroupTicket
	InvoiceCallbackSatdressProxy
	InvoiceCallbackGenerateDalle
)
View Source
const (
	MAX_SHOPS                    = 10
	MAX_ITEMS_PER_SHOP           = 20
	MAX_FILES_PER_ITEM           = 200
	SHOP_TITLE_MAX_LENGTH        = 50
	ITEM_TITLE_MAX_LENGTH        = 1500
	SHOPS_DESCRIPTION_MAX_LENGTH = 1500
)

Variables

View Source
var BotProfilePicture []byte
View Source
var ShopsNoShopsText = "*There are no shops here yet.*"
View Source
var ShopsText = ""

-------------- shops handler -------------- var ShopsText = "*Welcome to %s shop.*\n%s\nThere are %d shops here.\n%s"

View Source
var ShopsTextHelp = "⚠️ Shops are still in beta. Expect bugs."
View Source
var ShopsTextShopCount = "*Browse %d shops:*"
View Source
var ShopsTextWelcome = "*You are browsing %s shop.*"

Functions

func AssertEventType added in v0.5.1

func AssertEventType(event Event, eventType EventType) error

func ColumnMigrationTasks

func ColumnMigrationTasks(db *gorm.DB) error

func DownloadProfilePicture added in v0.5.1

func DownloadProfilePicture(telegram *tb.Bot, user *tb.User) ([]byte, error)

DownloadProfilePicture downloads a profile picture from Telegram. This is a public function because it is used in another package (lnurl)

func GetAmount added in v0.5.1

func GetAmount(input string) (amount int64, err error)

GetAmount parses an amount from a string like 1.2k or 3.50€ and returns the value in satoshis

func GetLnbitsUser

func GetLnbitsUser(u *tb.User, bot TipBot) (*lnbits.User, error)

GetLnbitsUser will not update the user in Database. this is required, because fetching lnbits.User from a incomplete tb.User will update the incomplete (partial) user in storage. this function will accept users like this: &tb.User{ID: toId, Username: username} without updating the user in storage.

func GetLnbitsUserWithSettings added in v0.5.1

func GetLnbitsUserWithSettings(u *tb.User, bot TipBot) (*lnbits.User, error)

func GetMemoFromCommand

func GetMemoFromCommand(command string, fromWord int) string

func GetUser

func GetUser(u *tb.User, bot TipBot) (*lnbits.User, error)

GetUser from Telegram user. Update the user if user information changed.

func GetUserByTelegramUsername

func GetUserByTelegramUsername(toUserStrWithoutAt string, bot TipBot) (*lnbits.User, error)

func GetUserStr

func GetUserStr(user *tb.User) string

func GetUserStrMd

func GetUserStrMd(user *tb.User) string

func LoadPublicLocalizer

func LoadPublicLocalizer(ctx context.Context) *i18n2.Localizer

LoadUser from context

func LoadReplyToUser

func LoadReplyToUser(ctx context.Context) *lnbits.User

LoadReplyToUser from context

func LoadUser

func LoadUser(ctx context.Context) *lnbits.User

LoadUser from context

func LoadUserLocalizer

func LoadUserLocalizer(ctx context.Context) *i18n2.Localizer

LoadUser from context

func MakeProgressbar

func MakeProgressbar(current int64, total int64) string

func MakeTipjarbar

func MakeTipjarbar(current int64, total int64) string

func ProfilePhotosOf added in v0.5.1

func ProfilePhotosOf(bot *tb.Bot, user *tb.User) ([]tb.Photo, error)

ProfilePhotosOf returns list of profile pictures for a user.

func RandStringRunes

func RandStringRunes(n int) string

func ResetUserState

func ResetUserState(user *lnbits.User, bot *TipBot)

func SetUserState

func SetUserState(user *lnbits.User, bot *TipBot, stateKey lnbits.UserStateKey, stateData string)

func TipCheckSyntax

func TipCheckSyntax(ctx context.Context, m *tb.Message) (bool, string)

func Translate

func Translate(ctx context.Context, MessgeID string) string

func TranslateUser

func TranslateUser(ctx context.Context, MessgeID string) string

func TryRecognizeQrCode

func TryRecognizeQrCode(img image.Image) (*gozxing.Result, error)

TryRecognizeInvoiceFromQrCode will try to read an invoice string from a qr code and invoke the payment ctx.

func UpdateUserRecord

func UpdateUserRecord(user *lnbits.User, bot TipBot) error

func UserGetAnonLNURL added in v0.5.1

func UserGetAnonLNURL(user *lnbits.User) (string, error)

func UserGetLNURL

func UserGetLNURL(user *lnbits.User) (string, error)

Types

type Cache

type Cache struct {
	*store.GoCacheStore
}
type ChatInviteLink struct {
	Ok     bool   `json:"ok"`
	Result Result `json:"result"`
}
type CreateChatInviteLink struct {
	ChatID             int64  `json:"chat_id"`
	Name               string `json:"name"`
	ExpiryDate         int    `json:"expiry_date"`
	MemberLimit        int    `json:"member_limit"`
	CreatesJoinRequest bool   `json:"creates_join_request"`
}

type Creator added in v0.5.1

type Creator struct {
	ID        int64  `json:"id"`
	IsBot     bool   `json:"is_bot"`
	Firstname string `json:"first_name"`
	Username  string `json:"username"`
}

type Databases added in v0.5.1

type Databases struct {
	Users        *gorm.DB
	Transactions *gorm.DB
	Groups       *gorm.DB
}

func AutoMigration

func AutoMigration() *Databases

type EditSingleButtonParams added in v0.5.1

type EditSingleButtonParams struct {
	Message    string
	ButtonText string
	Data       string
	URL        string
}

type EnterAmountStateData

type EnterAmountStateData struct {
	ID              string `json:"ID"`              // holds the ID of the tx object in bunt db
	Type            string `json:"Type"`            // holds type of the tx in bunt db (needed for type checking)
	Amount          int64  `json:"Amount"`          // holds the amount entered by the user mSat
	AmountMin       int64  `json:"AmountMin"`       // holds the minimum amount that needs to be entered mSat
	AmountMax       int64  `json:"AmountMax"`       // holds the maximum amount that needs to be entered mSat
	OiringalCommand string `json:"OiringalCommand"` // hold the originally entered command for evtl later use
}

type EnterUserStateData added in v0.4.2

type EnterUserStateData struct {
	ID              string `json:"ID"`              // holds the ID of the tx object in bunt db
	Type            string `json:"Type"`            // holds type of the tx in bunt db (needed for type checking)
	Amount          int64  `json:"Amount"`          // holds the amount entered by the user mSat
	AmountMin       int64  `json:"AmountMin"`       // holds the minimum amount that needs to be entered mSat
	AmountMax       int64  `json:"AmountMax"`       // holds the maximum amount that needs to be entered mSat
	OiringalCommand string `json:"OiringalCommand"` // hold the originally entered command for evtl later use
}

type Event added in v0.5.1

type Event interface {
	Type() EventType
}

type EventHandler added in v0.5.1

type EventHandler struct {
	Function func(event Event)
	Type     EventType
}

type EventType added in v0.5.1

type EventType string
const (
	EventTypeInvoice       EventType = "invoice"
	EventTypeTicketInvoice EventType = "ticket-invoice"
)

type Group added in v0.5.1

type Group struct {
	Name  string   `json:"name"`
	Title string   `json:"title"`
	ID    int64    `json:"id" gorm:"primaryKey"`
	Owner *tb.User `gorm:"embedded;embeddedPrefix:owner_"`
	// Chat   *tb.Chat `gorm:"embedded;embeddedPrefix:chat_"`
	Ticket *Ticket `gorm:"embedded;embeddedPrefix:ticket_"`
}

type InlineFaucet

type InlineFaucet struct {
	*storage.Base
	Message         string         `json:"inline_faucet_message"`
	Amount          int64          `json:"inline_faucet_amount"`
	RemainingAmount int64          `json:"inline_faucet_remainingamount"`
	PerUserAmount   int64          `json:"inline_faucet_peruseramount"`
	From            *lnbits.User   `json:"inline_faucet_from"`
	To              []*lnbits.User `json:"inline_faucet_to"`
	Memo            string         `json:"inline_faucet_memo"`
	NTotal          int            `json:"inline_faucet_ntotal"`
	NTaken          int            `json:"inline_faucet_ntaken"`
	UserNeedsWallet bool           `json:"inline_faucet_userneedswallet"`
	LanguageCode    string         `json:"languagecode"`
}

type InlineReceive

type InlineReceive struct {
	*storage.Base
	MessageText       string       `json:"inline_receive_messagetext"`
	Message           tb.Editable  `json:"inline_receive_message"`
	Amount            int64        `json:"inline_receive_amount"`
	From              *lnbits.User `json:"inline_receive_from"`
	To                *lnbits.User `json:"inline_receive_to"`
	From_SpecificUser bool         `json:"from_specific_user"`
	Memo              string       `json:"inline_receive_memo"`
	LanguageCode      string       `json:"languagecode"`
}

type InlineSend

type InlineSend struct {
	*storage.Base
	Message         string       `json:"inline_send_message"`
	Amount          int64        `json:"inline_send_amount"`
	From            *lnbits.User `json:"inline_send_from"`
	To              *lnbits.User `json:"inline_send_to"`
	To_SpecificUser bool         `json:"to_specific_user"`
	Memo            string       `json:"inline_send_memo"`
	LanguageCode    string       `json:"languagecode"`
}

type InlineTipjar

type InlineTipjar struct {
	*storage.Base
	Message       string         `json:"inline_tipjar_message"`
	Amount        int64          `json:"inline_tipjar_amount"`
	GivenAmount   int64          `json:"inline_tipjar_givenamount"`
	PerUserAmount int64          `json:"inline_tipjar_peruseramount"`
	To            *lnbits.User   `json:"inline_tipjar_to"`
	From          []*lnbits.User `json:"inline_tipjar_from"`
	Memo          string         `json:"inline_tipjar_memo"`
	NTotal        int            `json:"inline_tipjar_ntotal"`
	NGiven        int            `json:"inline_tipjar_ngiven"`
	LanguageCode  string         `json:"languagecode"`
}

type InterceptionWrapper added in v0.5.1

type InterceptionWrapper struct {
	Endpoints   []interface{}
	Handler     intercept.Func
	Interceptor *Interceptor
}

type Interceptor

type Interceptor struct {
	Before  []intercept.Func
	After   []intercept.Func
	OnDefer []intercept.Func
}

type Invoice added in v0.5.1

type Invoice struct {
	PaymentHash    string `json:"payment_hash"`
	PaymentRequest string `json:"payment_request"`
	Amount         int64  `json:"amount"`
	Memo           string `json:"memo"`
}

type InvoiceEvent added in v0.5.1

type InvoiceEvent struct {
	*Invoice
	*storage.Base
	User           *lnbits.User `json:"user"`                      // the user that is being paid
	Message        *tb.Message  `json:"message,omitempty"`         // the message that the invoice replies to
	InvoiceMessage *tb.Message  `json:"invoice_message,omitempty"` // the message that displays the invoice
	LanguageCode   string       `json:"languagecode"`              // language code of the user
	Callback       int          `json:"func"`                      // which function to call if the invoice is paid
	CallbackData   string       `json:"callbackdata"`              // add some data for the callback
	Chat           *tb.Chat     `json:"chat,omitempty"`            // if invoice is supposed to be sent to a particular chat
	Payer          *lnbits.User `json:"payer,omitempty"`           // if a particular user is supposed to pay this
}

func (InvoiceEvent) Key added in v0.5.1

func (invoiceEvent InvoiceEvent) Key() string

func (InvoiceEvent) Type added in v0.5.1

func (invoiceEvent InvoiceEvent) Type() EventType

type InvoiceEventCallback added in v0.5.1

type InvoiceEventCallback map[int]EventHandler
var InvoiceCallback InvoiceEventCallback

type InvoiceEventKey added in v0.5.1

type InvoiceEventKey int

type LNURLInvoice added in v0.5.1

type LNURLInvoice struct {
	*Invoice
	Comment   string       `json:"comment"`
	User      *lnbits.User `json:"user"`
	CreatedAt time.Time    `json:"created_at"`
	Paid      bool         `json:"paid"`
	PaidAt    time.Time    `json:"paid_at"`
	From      string       `json:"from"`
}

func (LNURLInvoice) Key added in v0.5.1

func (lnurlInvoice LNURLInvoice) Key() string

type LnurlAuthState added in v0.5.1

type LnurlAuthState struct {
	*storage.Base
	From            *lnbits.User          `json:"from"`
	LNURLAuthParams lnurl.LNURLAuthParams `json:"LNURLAuthParams"`
	Comment         string                `json:"comment"`
	LanguageCode    string                `json:"languagecode"`
	Message         *tb.Message           `json:"message"`
}

type LnurlPayState

type LnurlPayState struct {
	*storage.Base
	From            *lnbits.User         `json:"from"`
	LNURLPayParams  lnurl.LNURLPayParams `json:"LNURLPayParams"`
	LNURLPayValues  lnurl.LNURLPayValues `json:"LNURLPayValues"`
	Amount          int64                `json:"amount"`
	Comment         string               `json:"comment"`
	DescriptionHash string               `json:"descriptionHash,omitempty"`
	LanguageCode    string               `json:"languagecode"`
}

LnurlPayState saves the state of the user for an LNURL payment

type LnurlWithdrawState

type LnurlWithdrawState struct {
	*storage.Base
	From                  *lnbits.User                `json:"from"`
	LNURLWithdrawResponse lnurl.LNURLWithdrawResponse `json:"LNURLWithdrawResponse"`
	LNURResponse          lnurl.LNURLResponse         `json:"LNURLResponse"`
	Amount                int64                       `json:"amount"`
	Comment               string                      `json:"comment"`
	LanguageCode          string                      `json:"languagecode"`
	Success               bool                        `json:"success"`
	Invoice               lnbits.Invoice              `json:"invoice"`
	Message               string                      `json:"message"`
}

LnurlWithdrawState saves the state of the user for an LNURL payment

type Message

type Message struct {
	Message *tb.Message `json:"message"`
	// contains filtered or unexported fields
}

func NewMessage

func NewMessage(m *tb.Message, opts ...MessageOption) *Message

func (Message) Key

func (msg Message) Key() string

type MessageOption

type MessageOption func(m *Message)

func WithDuration

func WithDuration(duration time.Duration, tipBot *TipBot) MessageOption

type PayData

type PayData struct {
	*storage.Base
	From            *lnbits.User `json:"from"`
	Invoice         string       `json:"invoice"`
	Hash            string       `json:"hash"`
	Proof           string       `json:"proof"`
	Memo            string       `json:"memo"`
	Message         string       `json:"message"`
	Amount          int64        `json:"amount"`
	LanguageCode    string       `json:"languagecode"`
	TelegramMessage *tb.Message  `json:"telegrammessage"`
}

type Result added in v0.5.1

type Result struct {
	InviteLink         string  `json:"invite_link"`
	Name               string  `json:"name"`
	Creator            Creator `json:"creator"`
	CreatesJoinRequest bool    `json:"creates_join_request"`
	IsPrimary          bool    `json:"is_primary"`
	IsRevoked          bool    `json:"is_revoked"`
}

type SendData

type SendData struct {
	*storage.Base
	From           *lnbits.User `json:"from"`
	ToTelegramId   int64        `json:"to_telegram_id"`
	ToTelegramUser string       `json:"to_telegram_user"`
	Memo           string       `json:"memo"`
	Message        string       `json:"message"`
	Amount         int64        `json:"amount"`
	LanguageCode   string       `json:"languagecode"`
}

type Shop added in v0.5.1

type Shop struct {
	*storage.Base
	Owner        *lnbits.User        `json:"owner"`       // owner of the shop
	Type         string              `json:"Type"`        // type of the shop
	Title        string              `json:"title"`       // Title of the item
	Description  string              `json:"description"` // Description of the item
	ItemIds      []string            `json:"ItemsIDs"`    //
	Items        map[string]ShopItem `json:"Items"`       //
	LanguageCode string              `json:"languagecode"`
	ShopsID      string              `json:"shopsID"`
	MaxItems     int                 `json:"maxItems"`
}

type ShopItem added in v0.5.1

type ShopItem struct {
	ID           string       `json:"ID"`          // ID of the tx object in bunt db
	ShopID       string       `json:"shopID"`      // ID of the shop
	Owner        *lnbits.User `json:"owner"`       // Owner of the item
	Type         string       `json:"Type"`        // Type of the tx object in bunt db
	FileIDs      []string     `json:"fileIDs"`     // Telegram fileID of the item files
	FileTypes    []string     `json:"fileTypes"`   // Telegram file type of the item files
	Title        string       `json:"title"`       // Title of the item
	Description  string       `json:"description"` // Description of the item
	Price        int64        `json:"price"`       // price of the item
	NSold        int          `json:"nSold"`       // number of times item was sold
	TbPhoto      *tb.Photo    `json:"tbPhoto"`     // Telegram photo object
	LanguageCode string       `json:"languagecode"`
	MaxFiles     int          `json:"maxFiles"`
}

type ShopView added in v0.5.1

type ShopView struct {
	ID             string
	ShopID         string
	ShopOwner      *lnbits.User
	Page           int
	Message        *tb.Message
	StatusMessages []*tb.Message
}

type Shops added in v0.5.1

type Shops struct {
	*storage.Base
	Owner       *lnbits.User `json:"owner"` // owner of the shop
	Shops       []string     `json:"shop"`  //
	MaxShops    int          `json:"maxShops"`
	Description string       `json:"description"`
}

type StateCallbackMessage added in v0.5.1

type StateCallbackMessage map[lnbits.UserStateKey]func(ctx intercept.Context) (intercept.Context, error)

type Ticket added in v0.5.1

type Ticket struct {
	Price        int64        `json:"price"`
	Memo         string       `json:"memo"`
	Creator      *lnbits.User `gorm:"embedded;embeddedPrefix:creator_"`
	Cut          int64        `json:"cut"` // Percent to cut from ticket price
	BaseFee      int64        `json:"base_fee"`
	CutCheap     int64        `json:"cut_cheap"` // Percent to cut from ticket price
	BaseFeeCheap int64        `json:"base_fee_cheap"`
}

type TicketEvent added in v0.5.1

type TicketEvent struct {
	*storage.Base
	*InvoiceEvent
	Group *Group `gorm:"embedded;embeddedPrefix:group_"`
}

func (TicketEvent) Key added in v0.5.1

func (ticketEvent TicketEvent) Key() string

func (TicketEvent) Type added in v0.5.1

func (ticketEvent TicketEvent) Type() EventType

type TipBot

type TipBot struct {
	DB       *Databases
	Bunt     *storage.DB
	ShopBunt *storage.DB
	Telegram *tb.Bot
	Client   *lnbits.Client

	Cache
	// contains filtered or unexported fields
}

func NewBot

func NewBot() TipBot

NewBot migrates data and creates a new bot

func (*TipBot) CreateWalletForTelegramUser

func (bot *TipBot) CreateWalletForTelegramUser(tbUser *tb.User) (*lnbits.User, error)

func (*TipBot) DescriptionHash added in v0.5.1

func (bot *TipBot) DescriptionHash(metadata lnurl.Metadata, payerData string) (string, error)

DescriptionHash is the SHA256 hash of the metadata

func (*TipBot) GetUserBalance

func (bot *TipBot) GetUserBalance(user *lnbits.User) (amount int64, err error)

func (*TipBot) GetUserBalanceCached

func (bot *TipBot) GetUserBalanceCached(user *lnbits.User) (amount int64, err error)

func (*TipBot) GracefulShutdown added in v0.5.1

func (bot *TipBot) GracefulShutdown()

GracefulShutdown will gracefully shutdown the bot It will wait for all mutex locks to unlock before shutdown.

func (*TipBot) HandleLNURL added in v0.4.2

func (bot *TipBot) HandleLNURL(rawlnurl string) (string, lnurl.LNURLParams, error)

fiatjaf/go-lnurl 1.8.4 with proxy

func (*TipBot) SendCheckSyntax

func (bot *TipBot) SendCheckSyntax(ctx context.Context, m *tb.Message) (bool, string)

func (*TipBot) Start

func (bot *TipBot) Start()

Start will initialize the Telegram bot and lnbits.

func (*TipBot) UserExists

func (bot *TipBot) UserExists(user *tb.User) (*lnbits.User, bool)

func (*TipBot) UserGetAnonLightningAddress

func (bot *TipBot) UserGetAnonLightningAddress(user *lnbits.User) (string, error)

func (*TipBot) UserGetLightningAddress

func (bot *TipBot) UserGetLightningAddress(user *lnbits.User) (string, error)

func (*TipBot) UserIsBanned added in v0.5.1

func (bot *TipBot) UserIsBanned(user *lnbits.User) bool

type TipTooltip

type TipTooltip struct {
	Message
	ID        string     `json:"id"`
	TipAmount int64      `json:"tip_amount"`
	Ntips     int        `json:"ntips"`
	LastTip   time.Time  `json:"last_tip"`
	Tippers   []*tb.User `json:"tippers"`
}

func NewTipTooltip

func NewTipTooltip(m *tb.Message, opts ...TipTooltipOption) *TipTooltip

func (TipTooltip) Key

func (ttt TipTooltip) Key() string

type TipTooltipOption

type TipTooltipOption func(m *TipTooltip)

func TipAmount

func TipAmount(amount int64) TipTooltipOption

func Tips

func Tips(nTips int) TipTooltipOption

type Transaction

type Transaction struct {
	ID           uint           `gorm:"primarykey"`
	Time         time.Time      `json:"time"`
	Bot          *TipBot        `gorm:"-"`
	From         *lnbits.User   `json:"from" gorm:"-"`
	To           *lnbits.User   `json:"to" gorm:"-"`
	FromId       int64          `json:"from_id" `
	ToId         int64          `json:"to_id" `
	FromUser     string         `json:"from_user"`
	ToUser       string         `json:"to_user"`
	Type         string         `json:"type"`
	Amount       int64          `json:"amount"`
	ChatID       int64          `json:"chat_id"`
	ChatName     string         `json:"chat_name"`
	Memo         string         `json:"memo"`
	Success      bool           `json:"success"`
	FromWallet   string         `json:"from_wallet"`
	ToWallet     string         `json:"to_wallet"`
	FromLNbitsID string         `json:"from_lnbits"`
	ToLNbitsID   string         `json:"to_lnbits"`
	Invoice      lnbits.Invoice `gorm:"embedded;embeddedPrefix:invoice_"`
}

func NewTransaction

func NewTransaction(bot *TipBot, from *lnbits.User, to *lnbits.User, amount int64, opts ...TransactionOption) *Transaction

func (*Transaction) Send

func (t *Transaction) Send() (success bool, err error)

func (*Transaction) SendTransaction

func (t *Transaction) SendTransaction(bot *TipBot, from *lnbits.User, to *lnbits.User, amount int64, memo string) (bool, error)

type TransactionOption

type TransactionOption func(t *Transaction)

func TransactionChat

func TransactionChat(chat *tb.Chat) TransactionOption

func TransactionType

func TransactionType(transactionType string) TransactionOption

type TransactionsList added in v0.5.1

type TransactionsList struct {
	ID           string          `json:"id"`
	User         *lnbits.User    `json:"from"`
	Payments     lnbits.Payments `json:"payments"`
	LanguageCode string          `json:"languagecode"`
	CurrentPage  int             `json:"currentpage"`
	MaxPages     int             `json:"maxpages"`
	TxPerPage    int             `json:"txperpage"`
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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