Skip to content

Commit

Permalink
Revert "🔥 Removed favicon support - fixes makew0rld#199"
Browse files Browse the repository at this point in the history
  • Loading branch information
lovetocode999 committed Mar 6, 2021
1 parent f52d1a0 commit bf84185
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 5 deletions.
1 change: 0 additions & 1 deletion CHANGELOG.md
Expand Up @@ -6,7 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]
### Changed
- Favicon support removed (#199)
- Bookmarks are stored using XML in the XBEL format, old bookmarks are transferred (#68)
- Text no longer disappears under the left margin when scrolling (regression from v1.8.0) (#197)

Expand Down
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -141,6 +141,9 @@ Features in *italics* are in the master branch, but not in the latest release.
- [x] Download pages and arbitrary data
- [x] Theming
- Check out the [user contributed themes](https://github.com/makeworld-the-better-one/amfora/tree/master/contrib/themes)!
- [x] Emoji favicons
- See `gemini://mozz.us/files/rfc_gemini_favicon.gmi` for details
- Disabled by default, enable in config
- [x] Proxying
- Schemes like Gopher or HTTP can be proxied through a Gemini server
- [x] Client certificate support
Expand Down
51 changes: 51 additions & 0 deletions cache/favicon.go
@@ -0,0 +1,51 @@
package cache

import (
"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()
}
1 change: 1 addition & 0 deletions config/config.go
Expand Up @@ -202,6 +202,7 @@ func Init() error {
viper.SetDefault("a-general.temp_downloads", "")
viper.SetDefault("a-general.page_max_size", 2097152)
viper.SetDefault("a-general.page_max_time", 10)
viper.SetDefault("a-general.emoji_favicons", false)
viper.SetDefault("a-general.scrollbar", "auto")
viper.SetDefault("keybindings.bind_reload", []string{"R", "Ctrl-R"})
viper.SetDefault("keybindings.bind_home", "Backspace")
Expand Down
3 changes: 3 additions & 0 deletions config/default.go
Expand Up @@ -70,6 +70,9 @@ page_max_size = 2097152 # 2 MiB
# Max time it takes to load a page in seconds - after that a download window pops up
page_max_time = 10
# Whether to replace tab numbers with emoji favicons, which are cached.
emoji_favicons = false
# When a scrollbar appears. "never", "auto", and "always" are the only valid values.
# "auto" means the scrollbar only appears when the page is longer than the window.
scrollbar = "auto"
Expand Down
3 changes: 3 additions & 0 deletions default-config.toml
Expand Up @@ -67,6 +67,9 @@ page_max_size = 2097152 # 2 MiB
# Max time it takes to load a page in seconds - after that a download window pops up
page_max_time = 10

# Whether to replace tab numbers with emoji favicons, which are cached.
emoji_favicons = false

# When a scrollbar appears. "never", "auto", and "always" are the only valid values.
# "auto" means the scrollbar only appears when the page is longer than the window.
scrollbar = "auto"
Expand Down
13 changes: 10 additions & 3 deletions display/bookmarks.go
Expand Up @@ -85,8 +85,9 @@ func bkmkInit() {
// Bkmk displays the "Add a bookmark" modal.
// It accepts the default value for the bookmark name that will be displayed, but can be changed by the user.
// It also accepts a bool indicating whether this page already has a bookmark.
// It returns the bookmark name and the bookmark action.
func openBkmkModal(name string, exists bool) (string, bkmkAction) {
// It returns the bookmark name and the bookmark action:
// 1, 0, -1 for add/update, cancel, and remove
func openBkmkModal(name string, exists bool, favicon string) (string, int) {
// Basically a copy of Input()

// Reset buttons before input field, to make sure the input is in focus
Expand All @@ -101,7 +102,9 @@ func openBkmkModal(name string, exists bool) (string, bkmkAction) {

// Remove and re-add input field - to clear the old text
bkmkModal.GetForm().Clear(false)

if favicon != "" && !exists {
name = favicon + " " + name
}
bkmkModalText = name
bkmkModal.GetForm().AddInputField("Name: ", name, 0, nil,
func(text string) {
Expand Down Expand Up @@ -158,9 +161,13 @@ func addBookmark() {
}
name, exists := bookmarks.Get(p.URL)
// Open a bookmark modal with the current name of the bookmark, if it exists
<<<<<<< HEAD
newName, action := openBkmkModal(name, exists)

//nolint:exhaustive
=======
newName, action := openBkmkModal(name, exists, p.Favicon)
>>>>>>> 5d4d349 (Revert "🔥 Removed favicon support - fixes #199")
switch action {
case add:
bookmarks.Add(p.URL, newName)
Expand Down
2 changes: 2 additions & 0 deletions display/display.go
Expand Up @@ -549,8 +549,10 @@ func Reload() {
return
}

parsed, _ := url.Parse(tabs[curTab].page.URL)
go func(t *tab) {
cache.RemovePage(tabs[curTab].page.URL)
cache.RemoveFavicon(parsed.Host)
handleURL(t, t.page.URL, 0) // goURL is not used bc history shouldn't be added to
if t == tabs[curTab] {
// Display the bottomBar state that handleURL set
Expand Down
79 changes: 79 additions & 0 deletions display/handlers.go
@@ -1,12 +1,15 @@
package display

import (
"bytes"
"errors"
"io"
"mime"
"net"
"net/url"
"os/exec"
"path"
"strconv"
"strings"

"github.com/makeworld-the-better-one/amfora/cache"
Expand All @@ -18,6 +21,7 @@ import (
"github.com/makeworld-the-better-one/amfora/subscriptions"
"github.com/makeworld-the-better-one/amfora/webbrowser"
"github.com/makeworld-the-better-one/go-gemini"
"github.com/makeworld-the-better-one/go-isemoji"
"github.com/spf13/viper"
)

Expand Down Expand Up @@ -86,6 +90,81 @@ func handleOther(u string) {
App.Draw()
}

// handleFavicon handles getting and displaying a favicon.
func handleFavicon(t *tab, host string) {
defer func() {
// Update display if needed
if t.page.Favicon != "" && isValidTab(t) {
browser.SetTabLabel(strconv.Itoa(tabNumber(t)), makeTabLabel(t.page.Favicon))
App.Draw()
}
}()

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
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/") && res.Meta != "" {
// Not a textual page
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)
}

// handleAbout can be called to deal with any URLs that start with
// 'about:'. It will display errors if the URL is not recognized,
// but not display anything if an 'about:' URL is not passed.
Expand Down
5 changes: 5 additions & 0 deletions display/private.go
Expand Up @@ -117,6 +117,11 @@ func setPage(t *tab, p *structs.Page) {
)
App.Draw()

go func() {
parsed, _ := url.Parse(p.URL)
handleFavicon(t, parsed.Host)
}()

// Setup display
App.SetFocus(t.view)

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -8,6 +8,7 @@ require (
github.com/gdamore/tcell/v2 v2.1.1-0.20210125004847-19e17097d8fe
github.com/google/go-cmp v0.5.0 // indirect
github.com/makeworld-the-better-one/go-gemini v0.11.0
github.com/makeworld-the-better-one/go-isemoji v1.1.0
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.3.1 // indirect
github.com/mmcdole/gofeed v1.1.0
Expand All @@ -24,7 +25,6 @@ require (
golang.org/x/text v0.3.5
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
)

replace github.com/mmcdole/gofeed => github.com/makeworld-the-better-one/gofeed v1.1.1-0.20201123002655-c0c6354134fe
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -136,6 +136,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/makeworld-the-better-one/go-gemini v0.11.0 h1:MNGiULJFvcqls9oCy40tE897hDeKvNmEK9i5kRucgQk=
github.com/makeworld-the-better-one/go-gemini v0.11.0/go.mod h1:F+3x+R1xeYK90jMtBq+U+8Sh64r2dHleDZ/en3YgSmg=
github.com/makeworld-the-better-one/go-isemoji v1.1.0 h1:wZBHOKB5zAIgaU2vaWnXFDDhatebB8TySrNVxjVV84g=
github.com/makeworld-the-better-one/go-isemoji v1.1.0/go.mod h1:FBjkPl9rr0G4vlZCc+Mr+QcnOfGCTbGWYW8/1sp06I0=
github.com/makeworld-the-better-one/gofeed v1.1.1-0.20201123002655-c0c6354134fe h1:i3b9Qy5z23DcXRnrsMYcM5s9Ng5VIidM1xZd+szuTsY=
github.com/makeworld-the-better-one/gofeed v1.1.1-0.20201123002655-c0c6354134fe/go.mod h1:QQO3maftbOu+hiVOGOZDRLymqGQCos4zxbA4j89gMrE=
github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20201220005701-b036c4d38568 h1:fod4pD+rsU73WIUxl8Kpo35LDuOx0uxzlprBKbm84vw=
Expand Down
1 change: 1 addition & 0 deletions structs/structs.go
Expand Up @@ -33,6 +33,7 @@ type Page struct {
Selected string // The current text or link selected
SelectedID string // The cview region ID for the selected text/link
Mode PageMode
Favicon string
MadeAt time.Time // When the page was made. Zero value indicates it should stay in cache forever.
}

Expand Down

0 comments on commit bf84185

Please sign in to comment.