2020-06-24 03:07:25 +03:00
|
|
|
package bookmarks
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base32"
|
2021-02-27 08:13:11 +03:00
|
|
|
"encoding/xml"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2020-06-24 20:18:23 +03:00
|
|
|
"sort"
|
2020-06-24 03:07:25 +03:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/makeworld-the-better-one/amfora/config"
|
|
|
|
)
|
|
|
|
|
2021-02-27 08:13:11 +03:00
|
|
|
func Init() error {
|
|
|
|
f, err := os.Open(config.BkmkPath)
|
|
|
|
if err == nil {
|
|
|
|
// File exists and could be opened
|
2020-06-24 03:07:25 +03:00
|
|
|
|
2021-02-27 08:13:11 +03:00
|
|
|
fi, err := f.Stat()
|
|
|
|
if err == nil && fi.Size() > 0 {
|
|
|
|
// File is not empty
|
2020-06-24 03:07:25 +03:00
|
|
|
|
2021-02-27 08:13:11 +03:00
|
|
|
xbelBytes, err := ioutil.ReadAll(f)
|
|
|
|
f.Close()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("read bookmarks.xml error: %w", err)
|
|
|
|
}
|
|
|
|
err = xml.Unmarshal(xbelBytes, &data)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("bookmarks.xml is corrupted: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f.Close()
|
|
|
|
} else if !os.IsNotExist(err) {
|
|
|
|
// There's an error opening the file, but it's not bc is doesn't exist
|
|
|
|
return fmt.Errorf("open bookmarks.xml error: %w", err)
|
|
|
|
}
|
2020-06-24 03:07:25 +03:00
|
|
|
|
2021-02-27 08:13:11 +03:00
|
|
|
if data.Bookmarks == nil {
|
|
|
|
data.Bookmarks = make([]*xbelBookmark, 0)
|
|
|
|
data.Version = xbelVersion
|
|
|
|
}
|
2020-06-24 03:07:25 +03:00
|
|
|
|
2021-02-27 08:13:11 +03:00
|
|
|
if config.BkmkStore != nil {
|
|
|
|
// There's still bookmarks stored in the old format
|
|
|
|
// Add them and delete the file
|
2020-06-24 03:07:25 +03:00
|
|
|
|
2021-02-27 08:13:11 +03:00
|
|
|
names, urls := oldBookmarks()
|
|
|
|
for i := range names {
|
|
|
|
data.Bookmarks = append(data.Bookmarks, &xbelBookmark{
|
|
|
|
URL: urls[i],
|
|
|
|
Name: names[i],
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
err := writeXbel()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error saving old bookmarks into new format: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = os.Remove(config.OldBkmkPath)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf(
|
|
|
|
"couldn't delete old bookmarks file (%s), you must delete it yourself to prevent duplicate bookmarks: %w",
|
|
|
|
config.OldBkmkPath,
|
|
|
|
err,
|
2021-02-27 08:20:11 +03:00
|
|
|
) //nolint:goerr113,nolintlint
|
2021-02-27 08:13:11 +03:00
|
|
|
}
|
|
|
|
config.BkmkStore = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-06-24 03:07:25 +03:00
|
|
|
|
2021-02-27 08:13:11 +03:00
|
|
|
// oldBookmarks returns a slice of names and a slice of URLs of the
|
|
|
|
// bookmarks in config.BkmkStore.
|
|
|
|
func oldBookmarks() ([]string, []string) {
|
|
|
|
bkmksMap, ok := config.BkmkStore.AllSettings()["bookmarks"].(map[string]interface{})
|
2020-06-24 03:07:25 +03:00
|
|
|
if !ok {
|
|
|
|
// No bookmarks stored yet, return empty map
|
2021-02-27 08:13:11 +03:00
|
|
|
return []string{}, []string{}
|
2020-06-24 03:07:25 +03:00
|
|
|
}
|
2020-06-24 20:18:23 +03:00
|
|
|
|
2021-02-27 08:13:11 +03:00
|
|
|
names := make([]string, 0, len(bkmksMap))
|
|
|
|
urls := make([]string, 0, len(bkmksMap))
|
2020-06-24 20:18:23 +03:00
|
|
|
|
2020-06-24 03:07:25 +03:00
|
|
|
for b32Url, name := range bkmksMap {
|
|
|
|
if n, ok := name.(string); n == "" || !ok {
|
|
|
|
// name is not a string, or it's empty - ignore
|
2020-06-24 20:18:23 +03:00
|
|
|
// Likely means it is a removed bookmark
|
2020-06-24 03:07:25 +03:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
url, err := base32.StdEncoding.DecodeString(strings.ToUpper(b32Url))
|
|
|
|
if err != nil {
|
|
|
|
// This would only happen if a user messed around with the bookmarks file
|
|
|
|
continue
|
|
|
|
}
|
2020-06-24 20:18:23 +03:00
|
|
|
names = append(names, name.(string))
|
2021-02-27 08:13:11 +03:00
|
|
|
urls = append(urls, string(url))
|
|
|
|
}
|
|
|
|
return names, urls
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeXbel() error {
|
|
|
|
xbelBytes, err := xml.MarshalIndent(&data, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
xbelBytes = append(xbelHeader, xbelBytes...)
|
|
|
|
err = ioutil.WriteFile(config.BkmkPath, xbelBytes, 0666)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change the name of the bookmark at the provided URL.
|
|
|
|
func Change(url, name string) {
|
|
|
|
for _, bkmk := range data.Bookmarks {
|
|
|
|
if bkmk.URL == url {
|
|
|
|
bkmk.Name = name
|
|
|
|
writeXbel() //nolint:errcheck
|
|
|
|
return
|
|
|
|
}
|
2020-06-24 03:07:25 +03:00
|
|
|
}
|
2021-02-27 08:13:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add will add a new bookmark.
|
|
|
|
func Add(url, name string) {
|
|
|
|
data.Bookmarks = append(data.Bookmarks, &xbelBookmark{
|
|
|
|
URL: url,
|
|
|
|
Name: name,
|
|
|
|
})
|
|
|
|
writeXbel() //nolint:errcheck
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get returns the NAME of the bookmark, given the URL.
|
|
|
|
// It also returns a bool indicating whether it exists.
|
|
|
|
func Get(url string) (string, bool) {
|
|
|
|
for _, bkmk := range data.Bookmarks {
|
|
|
|
if bkmk.URL == url {
|
|
|
|
return bkmk.Name, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
|
|
|
func Remove(url string) {
|
|
|
|
for i, bkmk := range data.Bookmarks {
|
|
|
|
if bkmk.URL == url {
|
|
|
|
data.Bookmarks[i] = data.Bookmarks[len(data.Bookmarks)-1]
|
|
|
|
data.Bookmarks = data.Bookmarks[:len(data.Bookmarks)-1]
|
|
|
|
writeXbel() //nolint:errcheck
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// All returns all the bookmarks in a map of URLs to names.
|
|
|
|
// It also returns a slice of map keys, sorted so that the map *values*
|
|
|
|
// are in alphabetical order, with case ignored.
|
|
|
|
func All() (map[string]string, []string) {
|
|
|
|
bkmksMap := make(map[string]string)
|
|
|
|
|
|
|
|
inverted := make(map[string]string) // Holds inverted map, name->URL
|
|
|
|
names := make([]string, len(data.Bookmarks)) // Holds bookmark names, for sorting
|
|
|
|
keys := make([]string, len(data.Bookmarks)) // Final sorted keys (URLs), for returning at the end
|
|
|
|
|
|
|
|
for i, bkmk := range data.Bookmarks {
|
|
|
|
bkmksMap[bkmk.URL] = bkmk.Name
|
|
|
|
inverted[bkmk.Name] = bkmk.URL
|
|
|
|
names[i] = bkmk.Name
|
|
|
|
}
|
|
|
|
|
2020-06-24 20:18:23 +03:00
|
|
|
// Sort, then turn back into URL keys
|
|
|
|
sort.Strings(names)
|
2021-02-27 08:13:11 +03:00
|
|
|
for i, name := range names {
|
|
|
|
keys[i] = inverted[name]
|
2020-06-24 20:18:23 +03:00
|
|
|
}
|
|
|
|
|
2021-02-27 08:13:11 +03:00
|
|
|
return bkmksMap, keys
|
2020-06-24 03:07:25 +03:00
|
|
|
}
|