mirror of
https://github.com/makeworld-the-better-one/amfora.git
synced 2024-08-16 18:20:50 +03:00
✨ Emoji favicon support - fixes #62
This commit is contained in:
parent
edd128e7c5
commit
0bc5939600
@ -7,11 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
|
- Emoji favicons can now be seen if `emoji_favicons` is enabled in the config (#62)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Two digit (and higher) link texts are now in line with one digit ones (#60)
|
- Two digit (and higher) link texts are now in line with one digit ones (#60)
|
||||||
|
- Race condition when reloading pages, could have caused the cache to still be used
|
||||||
|
|
||||||
|
|
||||||
## [1.4.0] - 2020-07-28
|
## [1.4.0] - 2020-07-28
|
||||||
|
@ -97,7 +97,7 @@ Features in *italics* are in the master branch, but not in the latest release.
|
|||||||
- [x] Theming
|
- [x] Theming
|
||||||
- [ ] Subscribe to RSS and Atom feeds and display them
|
- [ ] Subscribe to RSS and Atom feeds and display them
|
||||||
- Subscribing to page changes, similar to how Spacewalk works, will also be supported
|
- Subscribing to page changes, similar to how Spacewalk works, will also be supported
|
||||||
- [ ] Emoji favicons
|
- [x] *Emoji favicons*
|
||||||
- See `gemini://mozz.us/files/rfc_gemini_favicon.gmi` for details
|
- See `gemini://mozz.us/files/rfc_gemini_favicon.gmi` for details
|
||||||
- [ ] Stream support
|
- [ ] Stream support
|
||||||
- [ ] Full client certificate UX within the client
|
- [ ] Full client certificate UX within the client
|
||||||
|
58
cache/favicons.go
vendored
Normal file
58
cache/favicons.go
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Functions for caching emoji favicons.
|
||||||
|
// See gemini://mozz.us/files/rfc_gemini_favicon.gmi for details.
|
||||||
|
|
||||||
|
var favicons = make(map[string]string) // domain to emoji
|
||||||
|
var favMu = sync.RWMutex{}
|
||||||
|
|
||||||
|
var KnownNoFavicon = "no"
|
||||||
|
|
||||||
|
// AddFavicon will add an emoji to the cache under that host.
|
||||||
|
// It does not verify that the string passed is actually an emoji.
|
||||||
|
// You can pass KnownNoFavicon as the emoji when a host doesn't have a valid favicon.
|
||||||
|
func AddFavicon(host, emoji string) {
|
||||||
|
favMu.Lock()
|
||||||
|
favicons[host] = emoji
|
||||||
|
favMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearFavicons removes all favicons from the cache
|
||||||
|
func ClearFavicons() {
|
||||||
|
favMu.Lock()
|
||||||
|
favicons = make(map[string]string)
|
||||||
|
favMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFavicon returns the favicon string for the host.
|
||||||
|
// It returns an empty string if there is no favicon cached.
|
||||||
|
// It might also return KnownNoFavicon to indicate that that host does not have
|
||||||
|
// a favicon at all.
|
||||||
|
func GetFavicon(host string) string {
|
||||||
|
favMu.RLock()
|
||||||
|
defer favMu.RUnlock()
|
||||||
|
return favicons[host]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NumFavicons() int {
|
||||||
|
favMu.RLock()
|
||||||
|
defer favMu.RUnlock()
|
||||||
|
return len(favicons)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveFavicon(host string) {
|
||||||
|
favMu.Lock()
|
||||||
|
delete(favicons, host)
|
||||||
|
favMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func AllFavicons() string {
|
||||||
|
favMu.RLock()
|
||||||
|
defer favMu.RUnlock()
|
||||||
|
return fmt.Sprintf("%v", favicons)
|
||||||
|
}
|
2
cache/redir.go
vendored
2
cache/redir.go
vendored
@ -31,8 +31,8 @@ func AddRedir(og, redir string) {
|
|||||||
// ClearRedirs removes all redirects from the cache.
|
// ClearRedirs removes all redirects from the cache.
|
||||||
func ClearRedirs() {
|
func ClearRedirs() {
|
||||||
redirMu.Lock()
|
redirMu.Lock()
|
||||||
defer redirMu.Unlock()
|
|
||||||
redirUrls = make(map[string]string)
|
redirUrls = make(map[string]string)
|
||||||
|
redirMu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect takes the provided URL and returns a redirected version, if a redirect
|
// Redirect takes the provided URL and returns a redirected version, if a redirect
|
||||||
|
@ -153,6 +153,7 @@ func Init() error {
|
|||||||
viper.SetDefault("a-general.downloads", "")
|
viper.SetDefault("a-general.downloads", "")
|
||||||
viper.SetDefault("a-general.page_max_size", 2097152)
|
viper.SetDefault("a-general.page_max_size", 2097152)
|
||||||
viper.SetDefault("a-general.page_max_time", 10)
|
viper.SetDefault("a-general.page_max_time", 10)
|
||||||
|
viper.SetDefault("a-general.emoji_favicons", false)
|
||||||
viper.SetDefault("cache.max_size", 0)
|
viper.SetDefault("cache.max_size", 0)
|
||||||
viper.SetDefault("cache.max_pages", 20)
|
viper.SetDefault("cache.max_pages", 20)
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ var defaultConf = []byte(`# This is the default config file.
|
|||||||
# example.com:123
|
# example.com:123
|
||||||
|
|
||||||
[a-general]
|
[a-general]
|
||||||
|
# Press Ctrl-H to access it
|
||||||
home = "gemini://gemini.circumlunar.space"
|
home = "gemini://gemini.circumlunar.space"
|
||||||
|
|
||||||
# What command to run to open a HTTP URL. Set to "default" to try to guess the browser,
|
# What command to run to open a HTTP URL. Set to "default" to try to guess the browser,
|
||||||
@ -19,21 +20,36 @@ home = "gemini://gemini.circumlunar.space"
|
|||||||
# If a command is set, than the URL will be added (in quotes) to the end of the command.
|
# If a command is set, than the URL will be added (in quotes) to the end of the command.
|
||||||
# A space will be prepended if necessary.
|
# A space will be prepended if necessary.
|
||||||
http = "default"
|
http = "default"
|
||||||
search = "gemini://gus.guru/search" # Any URL that will accept a query string can be put here
|
|
||||||
color = true # Whether colors will be used in the terminal
|
# Any URL that will accept a query string can be put here
|
||||||
bullets = true # Whether to replace list asterisks with unicode bullets
|
search = "gemini://gus.guru/search"
|
||||||
|
|
||||||
|
# Whether colors will be used in the terminal
|
||||||
|
color = true
|
||||||
|
|
||||||
|
# Whether to replace list asterisks with unicode bullets
|
||||||
|
bullets = true
|
||||||
|
|
||||||
# A number from 0 to 1, indicating what percentage of the terminal width the left margin should take up.
|
# A number from 0 to 1, indicating what percentage of the terminal width the left margin should take up.
|
||||||
left_margin = 0.15
|
left_margin = 0.15
|
||||||
max_width = 100 # The max number of columns to wrap a page's text to. Preformatted blocks are not wrapped.
|
|
||||||
|
# The max number of columns to wrap a page's text to. Preformatted blocks are not wrapped.
|
||||||
|
max_width = 100
|
||||||
|
|
||||||
# 'downloads' is the path to a downloads folder.
|
# 'downloads' is the path to a downloads folder.
|
||||||
# An empty value means the code will find the default downloads folder for your system.
|
# An empty value means the code will find the default downloads folder for your system.
|
||||||
# If the path does not exist it will be created.
|
# If the path does not exist it will be created.
|
||||||
downloads = ""
|
downloads = ""
|
||||||
|
|
||||||
# Max size for displayable content in bytes - after that size a download window pops up
|
# Max size for displayable content in bytes - after that size a download window pops up
|
||||||
page_max_size = 2097152 # 2 MiB
|
page_max_size = 2097152 # 2 MiB
|
||||||
# Max time it takes to load a page in seconds - after that a download window pops up
|
# Max time it takes to load a page in seconds - after that a download window pops up
|
||||||
page_max_time = 10
|
page_max_time = 10
|
||||||
|
|
||||||
|
# Whether to replace tab numbers with emoji favicons, which are cached.
|
||||||
|
emoji_favicons = false
|
||||||
|
|
||||||
|
|
||||||
# Options for page cache - which is only for text/gemini pages
|
# Options for page cache - which is only for text/gemini pages
|
||||||
# Increase the cache size to speed up browsing at the expense of memory
|
# Increase the cache size to speed up browsing at the expense of memory
|
||||||
[cache]
|
[cache]
|
||||||
@ -41,15 +57,16 @@ page_max_time = 10
|
|||||||
max_size = 0 # Size in bytes
|
max_size = 0 # Size in bytes
|
||||||
max_pages = 30 # The maximum number of pages the cache will store
|
max_pages = 30 # The maximum number of pages the cache will store
|
||||||
|
|
||||||
|
|
||||||
[theme]
|
[theme]
|
||||||
# This section is for changing the COLORS used in Amfora.
|
# This section is for changing the COLORS used in Amfora.
|
||||||
# These colors only apply if color is enabled above.
|
# These colors only apply if 'color' is enabled above.
|
||||||
# Colors can be set using a W3C color name, or a hex value such as #ffffff".
|
# Colors can be set using a W3C color name, or a hex value such as "#ffffff".
|
||||||
|
|
||||||
# Note that not all colors will work on terminals that do not have truecolor support.
|
# Note that not all colors will work on terminals that do not have truecolor support.
|
||||||
# If you want to stick to the standard 16 or 256 colors, you can get
|
# If you want to stick to the standard 16 or 256 colors, you can get
|
||||||
# a list of those here: https://jonasjacek.github.io/colors/
|
# a list of those here: https://jonasjacek.github.io/colors/
|
||||||
# Do NOT use the names from that site, just the hex codes.
|
# DO NOT use the names from that site, just the hex codes.
|
||||||
|
|
||||||
# Definitions:
|
# Definitions:
|
||||||
# bg = background
|
# bg = background
|
||||||
|
@ -486,24 +486,7 @@ func CloseTab() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tabPages.SwitchToPage(strconv.Itoa(curTab)) // Go to previous page
|
tabPages.SwitchToPage(strconv.Itoa(curTab)) // Go to previous page
|
||||||
// Rewrite the tab display
|
rewriteTabRow()
|
||||||
tabRow.Clear()
|
|
||||||
if viper.GetBool("a-general.color") {
|
|
||||||
for i := 0; i < NumTabs(); i++ {
|
|
||||||
fmt.Fprintf(tabRow, `["%d"][%s] %d [%s][""]|`,
|
|
||||||
i,
|
|
||||||
config.GetColorString("tab_num"),
|
|
||||||
i+1,
|
|
||||||
config.GetColorString("tab_divider"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i := 0; i < NumTabs(); i++ {
|
|
||||||
fmt.Fprintf(tabRow, `["%d"] %d [""]|`, i, i+1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tabRow.Highlight(strconv.Itoa(curTab)).ScrollToHighlight()
|
|
||||||
|
|
||||||
// Restore previous tab's state
|
// Restore previous tab's state
|
||||||
tabs[curTab].applyAll()
|
tabs[curTab].applyAll()
|
||||||
|
|
||||||
@ -550,8 +533,10 @@ func Reload() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go cache.RemovePage(tabs[curTab].page.Url)
|
parsed, _ := url.Parse(tabs[curTab].page.Url)
|
||||||
go func(t *tab) {
|
go func(t *tab) {
|
||||||
|
cache.RemovePage(tabs[curTab].page.Url)
|
||||||
|
cache.RemoveFavicon(parsed.Host)
|
||||||
handleURL(t, t.page.Url) // goURL is not used bc history shouldn't be added to
|
handleURL(t, t.page.Url) // goURL is not used bc history shouldn't be added to
|
||||||
if t == tabs[curTab] {
|
if t == tabs[curTab] {
|
||||||
// Display the bottomBar state that handleURL set
|
// Display the bottomBar state that handleURL set
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
package display
|
package display
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/makeworld-the-better-one/amfora/cache"
|
"github.com/makeworld-the-better-one/amfora/cache"
|
||||||
"github.com/makeworld-the-better-one/amfora/client"
|
"github.com/makeworld-the-better-one/amfora/client"
|
||||||
|
"github.com/makeworld-the-better-one/amfora/config"
|
||||||
"github.com/makeworld-the-better-one/amfora/renderer"
|
"github.com/makeworld-the-better-one/amfora/renderer"
|
||||||
"github.com/makeworld-the-better-one/amfora/structs"
|
"github.com/makeworld-the-better-one/amfora/structs"
|
||||||
"github.com/makeworld-the-better-one/amfora/webbrowser"
|
"github.com/makeworld-the-better-one/amfora/webbrowser"
|
||||||
"github.com/makeworld-the-better-one/go-gemini"
|
"github.com/makeworld-the-better-one/go-gemini"
|
||||||
|
"github.com/makeworld-the-better-one/go-isemoji"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"gitlab.com/tslocum/cview"
|
"gitlab.com/tslocum/cview"
|
||||||
)
|
)
|
||||||
@ -106,8 +112,16 @@ func setPage(t *tab, p *structs.Page) {
|
|||||||
// Make sure the page content is fitted to the terminal every time it's displayed
|
// Make sure the page content is fitted to the terminal every time it's displayed
|
||||||
reformatPage(p)
|
reformatPage(p)
|
||||||
|
|
||||||
// Change page on screen
|
oldFav := t.page.Favicon
|
||||||
|
|
||||||
t.page = p
|
t.page = p
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
parsed, _ := url.Parse(p.Url)
|
||||||
|
handleFavicon(t, parsed.Host, oldFav)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Change page on screen
|
||||||
t.view.SetText(p.Content)
|
t.view.SetText(p.Content)
|
||||||
t.view.Highlight("") // Turn off highlights, other funcs may restore if necessary
|
t.view.Highlight("") // Turn off highlights, other funcs may restore if necessary
|
||||||
t.view.ScrollToBeginning()
|
t.view.ScrollToBeginning()
|
||||||
@ -144,6 +158,81 @@ func handleHTTP(u string, showInfo bool) {
|
|||||||
App.Draw()
|
App.Draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleFavicon handles getting and displaying a favicon.
|
||||||
|
// `old` is the previous favicon for the tab.
|
||||||
|
func handleFavicon(t *tab, host, old string) {
|
||||||
|
defer func() {
|
||||||
|
// Update display if needed
|
||||||
|
if t.page.Favicon != old && isValidTab(t) {
|
||||||
|
rewriteTabRow()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if !viper.GetBool("a-general.emoji_favicons") {
|
||||||
|
// Not enabled
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if t.page.Favicon != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if host == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fav := cache.GetFavicon(host)
|
||||||
|
if fav == cache.KnownNoFavicon {
|
||||||
|
// It's been cached that this host doesn't have a favicon
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if fav != "" {
|
||||||
|
t.page.Favicon = fav
|
||||||
|
rewriteTabRow()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// No favicon cached
|
||||||
|
res, err := client.Fetch("gemini://" + host + "/favicon.txt")
|
||||||
|
if err != nil {
|
||||||
|
if res != nil {
|
||||||
|
res.Body.Close()
|
||||||
|
}
|
||||||
|
cache.AddFavicon(host, cache.KnownNoFavicon)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if res.Status != 20 {
|
||||||
|
cache.AddFavicon(host, cache.KnownNoFavicon)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(res.Meta, "text/plain") {
|
||||||
|
cache.AddFavicon(host, cache.KnownNoFavicon)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// It's a regular plain response
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
_, err = io.CopyN(buf, res.Body, 29+2+1) // 29 is the max emoji length, +2 for CRLF, +1 so that the right size will EOF
|
||||||
|
if err == nil {
|
||||||
|
// Content was too large
|
||||||
|
cache.AddFavicon(host, cache.KnownNoFavicon)
|
||||||
|
return
|
||||||
|
} else if err != io.EOF {
|
||||||
|
// Some network reading error
|
||||||
|
// No favicon is NOT known, could be a temporary error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// EOF, which is what we want.
|
||||||
|
emoji := strings.TrimRight(buf.String(), "\r\n")
|
||||||
|
if !isemoji.IsEmoji(emoji) {
|
||||||
|
cache.AddFavicon(host, cache.KnownNoFavicon)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Valid favicon found
|
||||||
|
t.page.Favicon = emoji
|
||||||
|
cache.AddFavicon(host, emoji)
|
||||||
|
}
|
||||||
|
|
||||||
// goURL is like handleURL, but takes care of history and the bottomBar.
|
// goURL is like handleURL, but takes care of history and the bottomBar.
|
||||||
// It should be preferred over handleURL in most cases.
|
// It should be preferred over handleURL in most cases.
|
||||||
// It has no return values to be processed.
|
// It has no return values to be processed.
|
||||||
@ -336,3 +425,32 @@ func handleURL(t *tab, u string) (string, bool) {
|
|||||||
go dlChoice("That file could not be displayed. What would you like to do?", u, res)
|
go dlChoice("That file could not be displayed. What would you like to do?", u, res)
|
||||||
return ret("", false)
|
return ret("", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rewriteTabRow clears the tabRow and writes all the tabs number/favicons into it.
|
||||||
|
func rewriteTabRow() {
|
||||||
|
tabRow.Clear()
|
||||||
|
if viper.GetBool("a-general.color") {
|
||||||
|
for i := 0; i < NumTabs(); i++ {
|
||||||
|
char := strconv.Itoa(i + 1)
|
||||||
|
if tabs[i].page.Favicon != "" {
|
||||||
|
char = tabs[i].page.Favicon
|
||||||
|
}
|
||||||
|
fmt.Fprintf(tabRow, `["%d"][%s] %s [%s][""]|`,
|
||||||
|
i,
|
||||||
|
config.GetColorString("tab_num"),
|
||||||
|
char,
|
||||||
|
config.GetColorString("tab_divider"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := 0; i < NumTabs(); i++ {
|
||||||
|
char := strconv.Itoa(i + 1)
|
||||||
|
if tabs[i].page.Favicon != "" {
|
||||||
|
char = tabs[i].page.Favicon
|
||||||
|
}
|
||||||
|
fmt.Fprintf(tabRow, `["%d"] %s [""]|`, i, char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabRow.Highlight(strconv.Itoa(curTab)).ScrollToHighlight()
|
||||||
|
App.Draw()
|
||||||
|
}
|
||||||
|
4
go.mod
4
go.mod
@ -7,6 +7,7 @@ require (
|
|||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606
|
github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606
|
||||||
github.com/makeworld-the-better-one/go-gemini v0.7.0
|
github.com/makeworld-the-better-one/go-gemini v0.7.0
|
||||||
|
github.com/makeworld-the-better-one/go-isemoji v1.0.0
|
||||||
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f
|
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/mitchellh/mapstructure v1.3.1 // indirect
|
github.com/mitchellh/mapstructure v1.3.1 // indirect
|
||||||
@ -16,10 +17,9 @@ require (
|
|||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/spf13/viper v1.7.0
|
github.com/spf13/viper v1.7.0
|
||||||
github.com/stretchr/testify v1.6.0
|
github.com/stretchr/testify v1.6.1
|
||||||
gitlab.com/tslocum/cview v1.4.8-0.20200713214710-cc7796c4ca44
|
gitlab.com/tslocum/cview v1.4.8-0.20200713214710-cc7796c4ca44
|
||||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 // indirect
|
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 // indirect
|
||||||
golang.org/x/text v0.3.3
|
golang.org/x/text v0.3.3
|
||||||
gopkg.in/ini.v1 v1.57.0 // indirect
|
gopkg.in/ini.v1 v1.57.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200603094226-e3079894b1e8 // indirect
|
|
||||||
)
|
)
|
||||||
|
10
go.sum
10
go.sum
@ -126,6 +126,8 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
|
|||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/makeworld-the-better-one/go-gemini v0.7.0 h1:TCerE47eYHLXj6RQDjfd5HdGVbcVqpBC6OoPBlyY7q4=
|
github.com/makeworld-the-better-one/go-gemini v0.7.0 h1:TCerE47eYHLXj6RQDjfd5HdGVbcVqpBC6OoPBlyY7q4=
|
||||||
github.com/makeworld-the-better-one/go-gemini v0.7.0/go.mod h1:P7/FbZ+IEIbA/d+A0Y3w2GNgD8SA2AcNv7aDGJbaWG4=
|
github.com/makeworld-the-better-one/go-gemini v0.7.0/go.mod h1:P7/FbZ+IEIbA/d+A0Y3w2GNgD8SA2AcNv7aDGJbaWG4=
|
||||||
|
github.com/makeworld-the-better-one/go-isemoji v1.0.0 h1:W3O4+qwtXeT8PUDzcQ1UjxiupQWgc/oJHpqwrllx3xM=
|
||||||
|
github.com/makeworld-the-better-one/go-isemoji v1.0.0/go.mod h1:FBjkPl9rr0G4vlZCc+Mr+QcnOfGCTbGWYW8/1sp06I0=
|
||||||
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f h1:YEUlTs5gb35UlBLTgqrub9axWTYB3d7/8TxrkJDZpRI=
|
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f h1:YEUlTs5gb35UlBLTgqrub9axWTYB3d7/8TxrkJDZpRI=
|
||||||
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f/go.mod h1:X6sxWNi9PBgQybpR4fpXPVD5fm7svLqZTQ5DJuERIoM=
|
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f/go.mod h1:X6sxWNi9PBgQybpR4fpXPVD5fm7svLqZTQ5DJuERIoM=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
@ -203,8 +205,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
@ -345,8 +347,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200603094226-e3079894b1e8 h1:jL/vaozO53FMfZLySWM+4nulF3gQEC6q5jH90LPomDo=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200603094226-e3079894b1e8/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -67,7 +67,6 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int) (*structs
|
|||||||
|
|
||||||
_, err := io.CopyN(buf, res.Body, viper.GetInt64("a-general.page_max_size")+1)
|
_, err := io.CopyN(buf, res.Body, viper.GetInt64("a-general.page_max_size")+1)
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
rawText := buf.Bytes()
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Content was larger than max size
|
// Content was larger than max size
|
||||||
return nil, ErrTooLarge
|
return nil, ErrTooLarge
|
||||||
@ -86,14 +85,14 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int) (*structs
|
|||||||
// Convert content first
|
// Convert content first
|
||||||
var utfText string
|
var utfText string
|
||||||
if isUTF8(params["charset"]) {
|
if isUTF8(params["charset"]) {
|
||||||
utfText = string(rawText)
|
utfText = buf.String()
|
||||||
} else {
|
} else {
|
||||||
encoding, err := ianaindex.MIME.Encoding(params["charset"])
|
encoding, err := ianaindex.MIME.Encoding(params["charset"])
|
||||||
if encoding == nil || err != nil {
|
if encoding == nil || err != nil {
|
||||||
// Some encoding doesn't exist and wasn't caught in CanDisplay()
|
// Some encoding doesn't exist and wasn't caught in CanDisplay()
|
||||||
return nil, errors.New("unsupported encoding")
|
return nil, errors.New("unsupported encoding")
|
||||||
}
|
}
|
||||||
utfText, err = encoding.NewDecoder().String(string(rawText))
|
utfText, err = encoding.NewDecoder().String(buf.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ type Page struct {
|
|||||||
Selected string // The current text or link selected
|
Selected string // The current text or link selected
|
||||||
SelectedID string // The cview region ID for the selected text/link
|
SelectedID string // The cview region ID for the selected text/link
|
||||||
Mode PageMode
|
Mode PageMode
|
||||||
|
Favicon string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns an approx. size of a Page in bytes.
|
// Size returns an approx. size of a Page in bytes.
|
||||||
|
Loading…
Reference in New Issue
Block a user