You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
4.1 KiB
209 lines
4.1 KiB
package main |
|
|
|
import ( |
|
"io" |
|
"io/ioutil" |
|
"log" |
|
"net/http" |
|
"os" |
|
"os/exec" |
|
"path/filepath" |
|
"regexp" |
|
"strings" |
|
|
|
"github.com/microcosm-cc/bluemonday" |
|
"github.com/rivo/tview" |
|
"golang.org/x/net/html" |
|
) |
|
|
|
type URL struct { |
|
Text string |
|
URL string |
|
Classes []string |
|
} |
|
|
|
func getURLs(text string) []URL { |
|
urlReg := regexp.MustCompile(`<a\s+?(.+?)>(.+?)<\/a>`) |
|
attrReg := regexp.MustCompile(`(\w+?)="(.+?)"`) |
|
matches := urlReg.FindAllStringSubmatch(text, -1) |
|
|
|
var urls []URL |
|
for _, m := range matches { |
|
url := URL{ |
|
Text: m[2], |
|
} |
|
attrs := attrReg.FindAllStringSubmatch(m[1], -1) |
|
if attrs == nil { |
|
continue |
|
} |
|
for _, a := range attrs { |
|
switch a[1] { |
|
case "href": |
|
url.URL = a[2] |
|
case "class": |
|
url.Classes = strings.Split(a[2], " ") |
|
} |
|
} |
|
urls = append(urls, url) |
|
} |
|
return urls |
|
} |
|
|
|
func cleanTootHTML(content string) (string, []URL) { |
|
stripped := bluemonday.NewPolicy().AllowElements("p", "br").AllowAttrs("href", "class").OnElements("a").Sanitize(content) |
|
urls := getURLs(stripped) |
|
stripped = bluemonday.NewPolicy().AllowElements("p", "br").Sanitize(content) |
|
stripped = strings.ReplaceAll(stripped, "<br>", "\n") |
|
stripped = strings.ReplaceAll(stripped, "<p>", "") |
|
stripped = strings.ReplaceAll(stripped, "</p>", "\n\n") |
|
stripped = strings.TrimSpace(stripped) |
|
stripped = html.UnescapeString(stripped) |
|
return stripped, urls |
|
} |
|
|
|
func openEditor(app *tview.Application, content string) (string, error) { |
|
f, err := ioutil.TempFile("", "tut") |
|
if err != nil { |
|
return "", err |
|
} |
|
if content != "" { |
|
_, err = f.WriteString(content) |
|
if err != nil { |
|
return "", err |
|
} |
|
} |
|
cmd := exec.Command("nvim", f.Name()) |
|
cmd.Stdin = os.Stdin |
|
cmd.Stdout = os.Stdout |
|
var text []byte |
|
app.Suspend(func() { |
|
err = cmd.Run() |
|
if err != nil { |
|
log.Fatalln(err) |
|
} |
|
f.Seek(0, 0) |
|
text, err = ioutil.ReadAll(f) |
|
}) |
|
if err != nil { |
|
return "", err |
|
} |
|
return strings.TrimSpace(string(text)), nil |
|
} |
|
|
|
func openURL(url string) { |
|
exec.Command("xdg-open", url).Start() |
|
} |
|
|
|
func openMedia(filenames []string) { |
|
for _, f := range filenames { |
|
exec.Command("xdg-open", f).Run() |
|
} |
|
for _, f := range filenames { |
|
os.Remove(f) |
|
} |
|
} |
|
|
|
func downloadFile(url string) (string, error) { |
|
f, err := ioutil.TempFile("", "tutfile") |
|
if err != nil { |
|
return "", err |
|
} |
|
defer f.Close() |
|
|
|
resp, err := http.Get(url) |
|
if err != nil { |
|
return "", err |
|
} |
|
defer resp.Body.Close() |
|
|
|
_, err = io.Copy(f, resp.Body) |
|
if err != nil { |
|
return "", nil |
|
} |
|
|
|
return f.Name(), nil |
|
} |
|
|
|
func getConfigDir() string { |
|
home, _ := os.LookupEnv("HOME") |
|
xdgConfig, exists := os.LookupEnv("XDG_CONFIG_HOME") |
|
if !exists { |
|
xdgConfig = home + "/.config" |
|
} |
|
xdgConfig += "/tut" |
|
return xdgConfig |
|
} |
|
|
|
func testConfigPath(name string) (string, error) { |
|
xdgConfig := getConfigDir() |
|
path := xdgConfig + "/" + name |
|
_, err := os.Stat(path) |
|
if os.IsNotExist(err) { |
|
return "", err |
|
} |
|
if err != nil { |
|
return "", err |
|
} |
|
return path, nil |
|
} |
|
|
|
func GetAccountsPath() (string, error) { |
|
return testConfigPath("accounts.yaml") |
|
} |
|
|
|
func GetConfigPath() (string, error) { |
|
return testConfigPath("config.yaml") |
|
} |
|
|
|
func CheckPath(input string, inclHidden bool) (string, bool) { |
|
info, err := os.Stat(input) |
|
if err != nil { |
|
return "", false |
|
} |
|
if !inclHidden && strings.HasPrefix(info.Name(), ".") { |
|
return "", false |
|
} |
|
|
|
if info.IsDir() { |
|
if input == "/" { |
|
return input, true |
|
} |
|
return input + "/", true |
|
} |
|
return input, true |
|
} |
|
|
|
func IsDir(input string) bool { |
|
info, err := os.Stat(input) |
|
if err != nil { |
|
return false |
|
} |
|
return info.IsDir() |
|
} |
|
|
|
func FindFiles(s string) []string { |
|
input := filepath.Clean(s) |
|
if len(s) > 2 && s[len(s)-2:] == "/." { |
|
input += "/." |
|
} |
|
var files []string |
|
path, exists := CheckPath(input, true) |
|
if exists { |
|
files = append(files, path) |
|
} |
|
|
|
base := filepath.Base(input) |
|
inclHidden := strings.HasPrefix(base, ".") || (len(input) > 1 && input[len(input)-2:] == "/.") |
|
matches, _ := filepath.Glob(input + "*") |
|
if strings.HasSuffix(path, "/") { |
|
matchesDir, _ := filepath.Glob(path + "*") |
|
matches = append(matches, matchesDir...) |
|
} |
|
for _, f := range matches { |
|
p, exists := CheckPath(f, inclHidden) |
|
if exists && p != path { |
|
files = append(files, p) |
|
} |
|
} |
|
return files |
|
}
|
|
|