models

package
v1.5.0 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2018 License: MIT Imports: 15 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APICollection

type APICollection struct {
	GuideSource          GuideSourceAPI
	GuideSourceChannel   GuideSourceChannelAPI
	GuideSourceProgramme GuideSourceProgrammeAPI
	Lineup               LineupAPI
	LineupChannel        LineupChannelAPI
	VideoSource          VideoSourceAPI
	VideoSourceTrack     VideoSourceTrackAPI
}

APICollection is a struct containing all models.

func NewAPICollection

func NewAPICollection(db *sqlx.DB, logger *logrus.Logger) *APICollection

NewAPICollection returns an initialized APICollection struct.

type ConvertibleBoolean

type ConvertibleBoolean bool

ConvertibleBoolean is a helper type to allow JSON documents using 0/1 or "true" and "false" be converted to bool.

func (ConvertibleBoolean) MarshalJSON

func (bit ConvertibleBoolean) MarshalJSON() ([]byte, error)

MarshalJSON returns a 0 or 1 depending on bool state.

func (*ConvertibleBoolean) MarshalXML

func (bit *ConvertibleBoolean) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML used to determine if the element is present or not. see https://stackoverflow.com/a/46516243

func (*ConvertibleBoolean) UnmarshalJSON

func (bit *ConvertibleBoolean) UnmarshalJSON(data []byte) error

UnmarshalJSON converts a 0, 1, true or false into a bool

func (*ConvertibleBoolean) UnmarshalXML

func (bit *ConvertibleBoolean) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML used to determine if the element is present or not. see https://stackoverflow.com/a/46516243

type DiscoveryData

type DiscoveryData struct {
	FriendlyName    string
	Manufacturer    string
	ModelName       string
	ModelNumber     string
	FirmwareName    string
	TunerCount      int
	FirmwareVersion string
	DeviceID        string
	DeviceAuth      string
	BaseURL         string
	LineupURL       string
	DeviceUUID      string
}

DiscoveryData contains data about telly to expose in the HDHomeRun format for Plex detection.

func (*DiscoveryData) UPNP

func (d *DiscoveryData) UPNP() upnp.RootDevice

UPNP returns the UPNP representation of the DiscoveryData.

type GuideSource

type GuideSource struct {
	ID              int              `db:"id"`
	Name            string           `db:"name"`
	Provider        string           `db:"provider"`
	Username        string           `db:"username"`
	Password        string           `db:"password"`
	URL             string           `db:"xmltv_url" json:"XMLTV_URL"`
	ProviderData    *json.RawMessage `db:"provider_data"`
	UpdateFrequency string           `db:"update_frequency"`
	ImportedAt      *time.Time       `db:"imported_at"`

	Channels []GuideSourceChannel `db:"-"`
}

GuideSource describes a source of EPG data.

func (*GuideSource) ProviderConfiguration

func (g *GuideSource) ProviderConfiguration() *guideproviders.Configuration

ProviderConfiguration returns a guideproviders.Configurator for the GuideSource.

type GuideSourceAPI

type GuideSourceAPI interface {
	InsertGuideSource(guideSourceStruct GuideSource, providerData interface{}) (*GuideSource, error)
	DeleteGuideSource(guideSourceID int) (*GuideSource, error)
	UpdateGuideSource(guideSourceID int, providerData interface{}) error
	GetGuideSourceByID(id int) (*GuideSource, error)
	GetAllGuideSources(includeChannels bool) ([]GuideSource, error)
	GetGuideSourcesForLineup(lineupID int) ([]GuideSource, error)
}

GuideSourceAPI contains all methods for the User struct

type GuideSourceChannel

type GuideSourceChannel struct {
	ID           int             `db:"id"`
	GuideID      int             `db:"guide_id"`
	XMLTVID      string          `db:"xmltv_id"`
	ProviderData json.RawMessage `db:"provider_data"`
	Data         json.RawMessage `db:"data"`
	ImportedAt   *time.Time      `db:"imported_at"`

	GuideSource          *GuideSource
	GuideSourceName      string
	GuideProviderChannel *guideproviders.Channel `json:"-"`
}

GuideSourceChannel is a single channel in a guide providers lineup.

type GuideSourceChannelAPI

type GuideSourceChannelAPI interface {
	InsertGuideSourceChannel(guideID int, channel guideproviders.Channel, providerData interface{}) (*GuideSourceChannel, error)
	DeleteGuideSourceChannel(channelID int) (*GuideSourceChannel, error)
	UpdateGuideSourceChannel(XMLTVID string, providerData interface{}) error
	GetGuideSourceChannelByID(id int, expanded bool) (*GuideSourceChannel, error)
	GetChannelsForGuideSource(guideSourceID int) ([]GuideSourceChannel, error)
}

GuideSourceChannelAPI contains all methods for the User struct

type GuideSourceChannelDB

type GuideSourceChannelDB struct {
	SQL        *sqlx.DB
	Collection *APICollection
}

GuideSourceChannelDB is a struct containing initialized the SQL connection as well as the APICollection.

func (*GuideSourceChannelDB) DeleteGuideSourceChannel

func (db *GuideSourceChannelDB) DeleteGuideSourceChannel(channelID int) (*GuideSourceChannel, error)

DeleteGuideSourceChannel marks a channel with the given ID as deleted.

func (*GuideSourceChannelDB) GetChannelsForGuideSource

func (db *GuideSourceChannelDB) GetChannelsForGuideSource(guideSourceID int) ([]GuideSourceChannel, error)

GetChannelsForGuideSource returns a slice of GuideSourceChannels for the given video source ID.

func (*GuideSourceChannelDB) GetGuideSourceChannelByID

func (db *GuideSourceChannelDB) GetGuideSourceChannelByID(id int, expanded bool) (*GuideSourceChannel, error)

GetGuideSourceChannelByID returns a single GuideSourceChannel for the given ID.

func (*GuideSourceChannelDB) InsertGuideSourceChannel

func (db *GuideSourceChannelDB) InsertGuideSourceChannel(guideID int, channel guideproviders.Channel, providerData interface{}) (*GuideSourceChannel, error)

InsertGuideSourceChannel inserts a new GuideSourceChannel into the database.

func (*GuideSourceChannelDB) UpdateGuideSourceChannel

func (db *GuideSourceChannelDB) UpdateGuideSourceChannel(XMLTVID string, providerData interface{}) error

UpdateGuideSourceChannel updates a channel.

type GuideSourceDB

type GuideSourceDB struct {
	SQL        *sqlx.DB
	Collection *APICollection
}

GuideSourceDB is a struct containing initialized the SQL connection as well as the APICollection.

func (*GuideSourceDB) DeleteGuideSource

func (db *GuideSourceDB) DeleteGuideSource(guideSourceID int) (*GuideSource, error)

DeleteGuideSource marks a guideSource with the given ID as deleted.

func (*GuideSourceDB) GetAllGuideSources

func (db *GuideSourceDB) GetAllGuideSources(includeChannels bool) ([]GuideSource, error)

GetAllGuideSources returns all video sources in the database.

func (*GuideSourceDB) GetGuideSourceByID

func (db *GuideSourceDB) GetGuideSourceByID(id int) (*GuideSource, error)

GetGuideSourceByID returns a single GuideSource for the given ID.

func (*GuideSourceDB) GetGuideSourcesForLineup

func (db *GuideSourceDB) GetGuideSourcesForLineup(lineupID int) ([]GuideSource, error)

GetGuideSourcesForLineup returns a slice of GuideSource for the given lineup ID.

func (*GuideSourceDB) InsertGuideSource

func (db *GuideSourceDB) InsertGuideSource(guideSourceStruct GuideSource, providerData interface{}) (*GuideSource, error)

InsertGuideSource inserts a new GuideSource into the database.

func (*GuideSourceDB) UpdateGuideSource

func (db *GuideSourceDB) UpdateGuideSource(guideSourceID int, providerData interface{}) error

UpdateGuideSource updates a guideSource.

type GuideSourceProgramme

type GuideSourceProgramme struct {
	GuideID      int             `db:"guide_id"`
	Channel      string          `db:"channel"`
	ProviderData json.RawMessage `db:"provider_data"`
	StartTime    *time.Time      `db:"start"`
	EndTime      *time.Time      `db:"end"`
	Date         *time.Time      `db:"date,omitempty"`
	Data         json.RawMessage `db:"data"`
	ImportedAt   *time.Time      `db:"imported_at"`

	XMLTV *xmltv.Programme `json:"-"`
}

GuideSourceProgramme is a single programme available in a guide providers lineup.

type GuideSourceProgrammeAPI

type GuideSourceProgrammeAPI interface {
	InsertGuideSourceProgramme(guideID int, programme xmltv.Programme, providerData interface{}) (*GuideSourceProgramme, error)
	DeleteGuideSourceProgrammesForChannel(channelID string) error
	UpdateGuideSourceProgramme(programmeID string, providerData interface{}) error
	GetGuideSourceProgrammeByID(id int) (*GuideSourceProgramme, error)
	GetProgrammesForActiveChannels() ([]GuideSourceProgramme, error)
	GetProgrammesForChannel(channelID string) ([]GuideSourceProgramme, error)
	GetProgrammesForGuideID(guideSourceID int) ([]GuideSourceProgramme, error)
}

GuideSourceProgrammeAPI contains all methods for the User struct

type GuideSourceProgrammeDB

type GuideSourceProgrammeDB struct {
	SQL        *sqlx.DB
	Collection *APICollection
}

GuideSourceProgrammeDB is a struct containing initialized the SQL connection as well as the APICollection. Why is it spelled like this instead of "program"? Matches XMLTV spec which this code is based on.

func (*GuideSourceProgrammeDB) DeleteGuideSourceProgrammesForChannel

func (db *GuideSourceProgrammeDB) DeleteGuideSourceProgrammesForChannel(channelID string) error

DeleteGuideSourceProgrammesForChannel marks a programme with the given ID as deleted.

func (*GuideSourceProgrammeDB) GetGuideSourceProgrammeByID

func (db *GuideSourceProgrammeDB) GetGuideSourceProgrammeByID(id int) (*GuideSourceProgramme, error)

GetGuideSourceProgrammeByID returns a single GuideSourceProgramme for the given ID.

func (*GuideSourceProgrammeDB) GetProgrammesForActiveChannels

func (db *GuideSourceProgrammeDB) GetProgrammesForActiveChannels() ([]GuideSourceProgramme, error)

GetProgrammesForActiveChannels returns a slice of GuideSourceProgrammes for actively assigned channels.

func (*GuideSourceProgrammeDB) GetProgrammesForChannel

func (db *GuideSourceProgrammeDB) GetProgrammesForChannel(channelID string) ([]GuideSourceProgramme, error)

GetProgrammesForChannel returns a slice of GuideSourceProgrammes for the given XMLTV channel ID.

func (*GuideSourceProgrammeDB) GetProgrammesForGuideID

func (db *GuideSourceProgrammeDB) GetProgrammesForGuideID(guideSourceID int) ([]GuideSourceProgramme, error)

GetProgrammesForGuideID returns a slice of GuideSourceProgrammes for the given guide ID.

func (*GuideSourceProgrammeDB) InsertGuideSourceProgramme

func (db *GuideSourceProgrammeDB) InsertGuideSourceProgramme(guideID int, programme xmltv.Programme, providerData interface{}) (*GuideSourceProgramme, error)

InsertGuideSourceProgramme inserts a new GuideSourceProgramme into the database.

func (*GuideSourceProgrammeDB) UpdateGuideSourceProgramme

func (db *GuideSourceProgrammeDB) UpdateGuideSourceProgramme(programmeID string, providerData interface{}) error

UpdateGuideSourceProgramme updates a programme.

type HDHomeRunLineupItem

type HDHomeRunLineupItem struct {
	XMLName     xml.Name           `xml:"Program"    json:"-"`
	AudioCodec  string             `xml:",omitempty" json:",omitempty"`
	DRM         ConvertibleBoolean `xml:",omitempty" json:",omitempty"`
	Favorite    ConvertibleBoolean `xml:",omitempty" json:",omitempty"`
	GuideName   string             `xml:",omitempty" json:",omitempty"`
	GuideNumber string             `xml:",omitempty" json:",omitempty"`
	HD          ConvertibleBoolean `xml:",omitempty" json:",omitempty"`
	URL         string             `xml:",omitempty" json:",omitempty"`
	VideoCodec  string             `xml:",omitempty" json:",omitempty"`
}

HDHomeRunLineupItem is a HDHomeRun specification compatible representation of a Track available in the lineup.

type Lineup

type Lineup struct {
	ID               int        `db:"id"`
	Name             string     `db:"name"`
	SSDP             bool       `db:"ssdp"`
	ListenAddress    string     `db:"listen_address"`
	DiscoveryAddress string     `db:"discovery_address"`
	Port             int        `db:"port"`
	Tuners           int        `db:"tuners"`
	Manufacturer     string     `db:"manufacturer"`
	ModelName        string     `db:"model_name"`
	ModelNumber      string     `db:"model_number"`
	FirmwareName     string     `db:"firmware_name"`
	FirmwareVersion  string     `db:"firmware_version"`
	DeviceID         string     `db:"device_id"`
	DeviceAuth       string     `db:"device_auth"`
	DeviceUUID       string     `db:"device_uuid"`
	StreamTransport  string     `db:"stream_transport"`
	CreatedAt        *time.Time `db:"created_at"`

	Channels []LineupChannel
}

Lineup describes a collection of channels exposed to the world with associated configuration.

func (*Lineup) GetDiscoveryData

func (s *Lineup) GetDiscoveryData() DiscoveryData

GetDiscoveryData returns DiscoveryData for the Lineup.

type LineupAPI

type LineupAPI interface {
	InsertLineup(lineupStruct Lineup) (*Lineup, error)
	DeleteLineup(lineupID int) (*Lineup, error)
	UpdateLineup(lineupID int, description string) (*Lineup, error)
	GetLineupByID(id int, withChannels bool) (*Lineup, error)
	GetEnabledLineups(withChannels bool) ([]Lineup, error)
}

LineupAPI contains all methods for the User struct

type LineupChannel

type LineupChannel struct {
	ID             int        `db:"id"`
	LineupID       int        `db:"lineup_id"`
	Title          string     `db:"title"`
	ChannelNumber  string     `db:"channel_number"`
	VideoTrackID   int        `db:"video_track_id"`
	GuideChannelID int        `db:"guide_channel_id"`
	HighDefinition bool       `db:"hd" json:"HD"`
	Favorite       bool       `db:"favorite"`
	CreatedAt      *time.Time `db:"created_at"`

	VideoTrack   *VideoSourceTrack    `json:",omitempty"`
	GuideChannel *GuideSourceChannel  `json:",omitempty"`
	HDHR         *HDHomeRunLineupItem `json:",omitempty"`
	// contains filtered or unexported fields
}

LineupChannel is a single channel available in a Lineup.

func (*LineupChannel) Fill

func (l *LineupChannel) Fill(api *APICollection)

Fill will insert Lineup, GuideChannel and VideoTrack into the LineupChannel.

func (*LineupChannel) HDHomeRunLineupItem

func (l *LineupChannel) HDHomeRunLineupItem() *HDHomeRunLineupItem

HDHomeRunLineupItem returns a HDHomeRunLineupItem for the LineupChannel.

func (*LineupChannel) String

func (l *LineupChannel) String() string

type LineupChannelAPI

type LineupChannelAPI interface {
	InsertLineupChannel(channelStruct LineupChannel) (*LineupChannel, error)
	UpsertLineupChannel(channelStruct LineupChannel) (*LineupChannel, error)
	DeleteLineupChannel(channelID string) error
	UpdateLineupChannel(channelStruct LineupChannel) (*LineupChannel, error)
	GetLineupChannelByID(lineupID int, channelNumber string) (*LineupChannel, error)
	GetChannelsForLineup(lineupID int, expanded bool) ([]LineupChannel, error)
	GetEnabledChannelsForGuideProvider(providerID int) ([]LineupChannel, error)
	GetEnabledChannelsForVideoProvider(providerID int) ([]LineupChannel, error)
}

LineupChannelAPI contains all methods for the User struct

type LineupChannelDB

type LineupChannelDB struct {
	SQL        *sqlx.DB
	Collection *APICollection
}

LineupChannelDB is a struct containing initialized the SQL connection as well as the APICollection.

func (*LineupChannelDB) DeleteLineupChannel

func (db *LineupChannelDB) DeleteLineupChannel(channelID string) error

DeleteLineupChannel marks a channel with the given ID as deleted.

func (*LineupChannelDB) GetChannelsForLineup

func (db *LineupChannelDB) GetChannelsForLineup(lineupID int, expanded bool) ([]LineupChannel, error)

GetChannelsForLineup returns a slice of LineupChannels for the given lineup ID.

func (*LineupChannelDB) GetEnabledChannelsForGuideProvider

func (db *LineupChannelDB) GetEnabledChannelsForGuideProvider(providerID int) ([]LineupChannel, error)

GetEnabledChannelsForGuideProvider returns a slice of LineupChannels for the given guide provider ID.

func (*LineupChannelDB) GetEnabledChannelsForVideoProvider

func (db *LineupChannelDB) GetEnabledChannelsForVideoProvider(providerID int) ([]LineupChannel, error)

GetEnabledChannelsForVideoProvider returns a slice of LineupChannels for the given video provider ID.

func (*LineupChannelDB) GetLineupChannelByID

func (db *LineupChannelDB) GetLineupChannelByID(lineupID int, channelNumber string) (*LineupChannel, error)

GetLineupChannelByID returns a single LineupChannel for the given ID.

func (*LineupChannelDB) InsertLineupChannel

func (db *LineupChannelDB) InsertLineupChannel(channelStruct LineupChannel) (*LineupChannel, error)

InsertLineupChannel inserts a new LineupChannel into the database.

func (*LineupChannelDB) UpdateLineupChannel

func (db *LineupChannelDB) UpdateLineupChannel(channelStruct LineupChannel) (*LineupChannel, error)

UpdateLineupChannel updates a channel.

func (*LineupChannelDB) UpsertLineupChannel

func (db *LineupChannelDB) UpsertLineupChannel(channelStruct LineupChannel) (*LineupChannel, error)

UpsertLineupChannel upserts a LineupChannel in the database.

type LineupDB

type LineupDB struct {
	SQL        *sqlx.DB
	Collection *APICollection
}

LineupDB is a struct containing initialized the SQL connection as well as the APICollection.

func (*LineupDB) DeleteLineup

func (db *LineupDB) DeleteLineup(lineupID int) (*Lineup, error)

DeleteLineup marks a lineup with the given ID as deleted.

func (*LineupDB) GetEnabledLineups

func (db *LineupDB) GetEnabledLineups(withChannels bool) ([]Lineup, error)

GetEnabledLineups returns all enabled lineups in the database.

func (*LineupDB) GetLineupByID

func (db *LineupDB) GetLineupByID(id int, withChannels bool) (*Lineup, error)

GetLineupByID returns a single Lineup for the given ID.

func (*LineupDB) InsertLineup

func (db *LineupDB) InsertLineup(lineupStruct Lineup) (*Lineup, error)

InsertLineup inserts a new Lineup into the database.

func (*LineupDB) UpdateLineup

func (db *LineupDB) UpdateLineup(lineupID int, description string) (*Lineup, error)

UpdateLineup updates a lineup.

type VideoSource

type VideoSource struct {
	ID              int        `db:"id"`
	Name            string     `db:"name"`
	Provider        string     `db:"provider"`
	Username        string     `db:"username"`
	Password        string     `db:"password"`
	BaseURL         string     `db:"base_url"`
	M3UURL          string     `db:"m3u_url"`
	MaxStreams      int        `db:"max_streams"`
	UpdateFrequency string     `db:"update_frequency"`
	ImportedAt      *time.Time `db:"imported_at"`

	Tracks []VideoSourceTrack `db:"tracks"`
}

VideoSource is a source of video streams.

func (*VideoSource) ProviderConfiguration

func (v *VideoSource) ProviderConfiguration() *videoproviders.Configuration

ProviderConfiguration returns an initialized videoproviders.Configuration for the VideoSource.

type VideoSourceAPI

type VideoSourceAPI interface {
	InsertVideoSource(videoSourceStruct VideoSource) (*VideoSource, error)
	DeleteVideoSource(videoSourceID int) (*VideoSource, error)
	UpdateVideoSource(videoSourceID int, description string) (*VideoSource, error)
	GetVideoSourceByID(id int) (*VideoSource, error)
	GetAllVideoSources(includeTracks bool) ([]VideoSource, error)
}

VideoSourceAPI contains all methods for the User struct

type VideoSourceDB

type VideoSourceDB struct {
	SQL        *sqlx.DB
	Collection *APICollection
}

VideoSourceDB is a struct containing initialized the SQL connection as well as the APICollection.

func (*VideoSourceDB) DeleteVideoSource

func (db *VideoSourceDB) DeleteVideoSource(videoSourceID int) (*VideoSource, error)

DeleteVideoSource marks a videoSource with the given ID as deleted.

func (*VideoSourceDB) GetAllVideoSources

func (db *VideoSourceDB) GetAllVideoSources(includeTracks bool) ([]VideoSource, error)

GetAllVideoSources returns all video sources in the database.

func (*VideoSourceDB) GetVideoSourceByID

func (db *VideoSourceDB) GetVideoSourceByID(id int) (*VideoSource, error)

GetVideoSourceByID returns a single VideoSource for the given ID.

func (*VideoSourceDB) InsertVideoSource

func (db *VideoSourceDB) InsertVideoSource(videoSourceStruct VideoSource) (*VideoSource, error)

InsertVideoSource inserts a new VideoSource into the database.

func (*VideoSourceDB) UpdateVideoSource

func (db *VideoSourceDB) UpdateVideoSource(videoSourceID int, description string) (*VideoSource, error)

UpdateVideoSource updates a videoSource.

type VideoSourceTrack

type VideoSourceTrack struct {
	ID            int        `db:"id"`
	VideoSourceID int        `db:"video_source_id"`
	Name          string     `db:"name"`
	StreamID      int        `db:"stream_id"`
	Type          string     `db:"type"`
	Category      string     `db:"category"`
	EPGID         string     `db:"epg_id"`
	ImportedAt    *time.Time `db:"imported_at"`

	VideoSource     *VideoSource
	VideoSourceName string
}

VideoSourceTrack is a single stream available from a video source.

type VideoSourceTrackAPI

type VideoSourceTrackAPI interface {
	InsertVideoSourceTrack(trackStruct VideoSourceTrack) (*VideoSourceTrack, error)
	DeleteVideoSourceTrack(trackID int) (*VideoSourceTrack, error)
	UpdateVideoSourceTrack(providerID, trackID int, trackStruct VideoSourceTrack) error
	GetVideoSourceTrackByID(id int, expanded bool) (*VideoSourceTrack, error)
	GetTracksForVideoSource(videoSourceID int) ([]VideoSourceTrack, error)
}

VideoSourceTrackAPI contains all methods for the User struct

type VideoSourceTrackDB

type VideoSourceTrackDB struct {
	SQL        *sqlx.DB
	Collection *APICollection
}

VideoSourceTrackDB is a struct containing initialized the SQL connection as well as the APICollection.

func (*VideoSourceTrackDB) DeleteVideoSourceTrack

func (db *VideoSourceTrackDB) DeleteVideoSourceTrack(trackID int) (*VideoSourceTrack, error)

DeleteVideoSourceTrack marks a track with the given ID as deleted.

func (*VideoSourceTrackDB) GetTracksForVideoSource

func (db *VideoSourceTrackDB) GetTracksForVideoSource(videoSourceID int) ([]VideoSourceTrack, error)

GetTracksForVideoSource returns a slice of VideoSourceTracks for the given video source ID.

func (*VideoSourceTrackDB) GetVideoSourceTrackByID

func (db *VideoSourceTrackDB) GetVideoSourceTrackByID(id int, expanded bool) (*VideoSourceTrack, error)

GetVideoSourceTrackByID returns a single VideoSourceTrack for the given ID.

func (*VideoSourceTrackDB) InsertVideoSourceTrack

func (db *VideoSourceTrackDB) InsertVideoSourceTrack(trackStruct VideoSourceTrack) (*VideoSourceTrack, error)

InsertVideoSourceTrack inserts a new VideoSourceTrack into the database.

func (*VideoSourceTrackDB) UpdateVideoSourceTrack

func (db *VideoSourceTrackDB) UpdateVideoSourceTrack(providerID, streamID int, trackStruct VideoSourceTrack) error

UpdateVideoSourceTrack updates a track.

Jump to

Keyboard shortcuts

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