mastodon-markdown-archive/files/files.go

183 lines
3.6 KiB
Go
Raw Normal View History

package files
import (
"fmt"
2024-05-08 23:13:10 +00:00
"io"
"mime"
"net/http"
"os"
"path/filepath"
"text/template"
2024-05-08 23:13:10 +00:00
"git.garrido.io/gabriel/mastodon-pesos/client"
md "github.com/JohannesKaufmann/html-to-markdown"
)
type FileWriter struct {
dir string
repies map[string]client.Post
}
type TemplateContext struct {
2024-04-21 16:43:55 +00:00
Post client.Post
Descendants []client.Post
}
func New(dir string) (FileWriter, error) {
var fileWriter FileWriter
_, err := os.Stat(dir)
if os.IsNotExist(err) {
os.Mkdir(dir, os.ModePerm)
}
absDir, err := filepath.Abs(dir)
if err != nil {
return fileWriter, err
}
return FileWriter{
dir: absDir,
repies: make(map[string]client.Post),
}, nil
}
2024-04-21 16:43:55 +00:00
func (f FileWriter) Write(post client.Post) error {
tpmlFilename := "templates/post.tmpl"
tmplFile, err := filepath.Abs(tpmlFilename)
if err != nil {
2024-04-21 16:43:55 +00:00
return fmt.Errorf("error resolving template absolute path: %w", err)
}
if post.InReplyToId != "" {
f.repies[post.InReplyToId] = post
2024-04-21 16:43:55 +00:00
return nil
}
var descendants []client.Post
f.getReplies(post.Id, &descendants)
2024-05-08 23:13:10 +00:00
var file *os.File
if len(post.MediaAttachments) == 0 {
name := fmt.Sprintf("%s.md", post.Id)
filename := filepath.Join(f.dir, name)
file, err = os.Create(filename)
} else {
dir := filepath.Join(f.dir, post.Id)
imagedir := filepath.Join(dir, "images")
os.Mkdir(dir, os.ModePerm)
os.Mkdir(imagedir, os.ModePerm)
for i := 0; i < len(post.MediaAttachments); i++ {
media := &post.MediaAttachments[i]
if media.Type != "image" {
continue
}
image, err := downloadAttachment(imagedir, media.Id, media.Url)
if err != nil {
return err
}
media.Path = fmt.Sprintf("images/%s", image)
}
if err != nil {
return fmt.Errorf("error downloading media attachments: %w", err)
}
filename := filepath.Join(dir, "index.md")
file, err = os.Create(filename)
}
if err != nil {
2024-04-21 16:43:55 +00:00
return fmt.Errorf("error creating file: %w", err)
}
defer file.Close()
2024-04-21 16:43:55 +00:00
converter := md.NewConverter("", true, nil)
funcs := template.FuncMap{
"tomd": converter.ConvertString,
}
tmpl, err := template.New(filepath.Base(tpmlFilename)).Funcs(funcs).ParseFiles(tmplFile)
context := TemplateContext{
2024-04-21 16:43:55 +00:00
Post: post,
Descendants: descendants,
}
err = tmpl.Execute(file, context)
if err != nil {
2024-04-21 16:43:55 +00:00
return fmt.Errorf("error executing template: %w", err)
}
2024-04-21 16:43:55 +00:00
return nil
}
func (f FileWriter) getReplies(postId string, replies *[]client.Post) {
if reply, ok := f.repies[postId]; ok {
*replies = append(*replies, reply)
f.getReplies(reply.Id, replies)
}
}
2024-05-08 23:13:10 +00:00
func downloadAttachment(dir string, id string, url string) (string, error) {
var filename string
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Accept", "image/*")
res, err := client.Do(req)
if err != nil {
return filename, err
}
defer res.Body.Close()
contentType := res.Header.Get("Content-Type")
extensions, err := mime.ExtensionsByType(contentType)
if err != nil {
return filename, err
}
var ext string
urlExt := filepath.Ext(url)
for _, i := range extensions {
if i == urlExt {
ext = i
break
}
}
if ext == "" {
return filename, fmt.Errorf("Could not match extension for media")
}
filename = fmt.Sprintf("%s%s", id, ext)
file, err := os.Create(filepath.Join(dir, filename))
if err != nil {
return filename, err
}
defer file.Close()
_, err = io.Copy(file, res.Body)
if err != nil {
return filename, err
}
return filename, nil
}