Created
February 16, 2022 21:18
-
-
Save codemicro/f26e0d38cc00beef0f84a25ba505476a to your computer and use it in GitHub Desktop.
Go program to export Google Keep data to GitJournal Markdown format
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"io" | |
"io/fs" | |
"io/ioutil" | |
"os" | |
"path" | |
"strings" | |
"time" | |
) | |
var ( | |
inputDir = os.Args[1] | |
outputDir = os.Args[2] | |
) | |
func main() { | |
if err := run(); err != nil { | |
fmt.Fprintf(os.Stderr, "Unhandled error: %v", err) | |
os.Exit(1) | |
} | |
} | |
type file struct { | |
Attachments []struct { | |
FilePath string `json:"filePath"` | |
Mimetype string `json:"mimetype"` | |
} `json:"attachments"` | |
TextContent string `json:"textContent"` | |
Title string `json:"title"` | |
ListContent []struct { | |
Text string `json:"text"` | |
IsChecked bool `json:"isChecked"` | |
} `json:"listContent"` | |
UserEditedTimestampUsec int64 `json:"userEditedTimestampUsec"` | |
CreatedTimestampUsec int64 `json:"createdTimestampUsec"` | |
Labels []struct { | |
Name string `json:"name"` | |
} `json:"labels"` | |
} | |
func run() error { | |
_ = os.MkdirAll(outputDir, os.ModeDir) | |
inputDirFS := os.DirFS(inputDir) | |
inputJSONFiles, err := fs.Glob(inputDirFS, "*.json") | |
if err != nil { | |
return err | |
} | |
for _, filename := range inputJSONFiles { | |
fullpath := path.Join(inputDir, filename) | |
f, err := parseNoteFile(fullpath) | |
if err != nil { | |
return err | |
} | |
if err := ioutil.WriteFile( | |
path.Join(outputDir, time.UnixMicro(f.CreatedTimestampUsec).Format("2006-01-02-15-04-05")+".md"), | |
[]byte(f.ToMarkdown()), | |
0644, | |
); err != nil { | |
return err | |
} | |
if err := f.CopyAttachments(inputDirFS, outputDir); err != nil { | |
return err | |
} | |
} | |
return nil | |
} | |
func parseNoteFile(filename string) (*file, error) { | |
fcont, err := ioutil.ReadFile(filename) | |
if err != nil { | |
return nil, err | |
} | |
f := new(file) | |
if err := json.Unmarshal(fcont, f); err != nil { | |
return nil, err | |
} | |
return f, nil | |
} | |
func addYAMLParameter(sbr *strings.Builder, name, content string) { | |
(*sbr).WriteString(name) | |
(*sbr).WriteString(": ") | |
(*sbr).WriteString(content) | |
(*sbr).WriteString("\n") | |
} | |
func (f *file) ToMarkdown() string { | |
const timeFormat = "2006-01-02 15:04:05 -0700" | |
var sb strings.Builder | |
sb.WriteString("---\n") | |
addYAMLParameter( | |
&sb, | |
"created", | |
time.UnixMicro(f.CreatedTimestampUsec).Format(timeFormat), | |
) | |
addYAMLParameter( | |
&sb, | |
"modified", | |
time.UnixMicro(f.UserEditedTimestampUsec).Format(timeFormat), | |
) | |
addYAMLParameter( | |
&sb, | |
"title", | |
f.Title, | |
) | |
if len(f.ListContent) != 0 { | |
addYAMLParameter( | |
&sb, | |
"type", | |
"Checklist", | |
) | |
} | |
sb.WriteString("---\n") | |
if len(f.ListContent) != 0 { | |
for _, item := range f.ListContent { | |
sb.WriteString("- [") | |
mark := " " | |
if item.IsChecked { | |
mark = "x" | |
} | |
sb.WriteString(mark) | |
sb.WriteString("] ") | |
sb.WriteString(strings.ReplaceAll(strings.TrimSpace(item.Text), "\n", "\n ")) | |
sb.WriteString("\n") | |
} | |
} else { | |
sb.WriteString(strings.ReplaceAll(strings.TrimSpace(f.TextContent), "\n", "\n\n")) | |
} | |
for _, img := range f.Attachments { | |
sb.WriteString("\n\n | |
sb.WriteString(img.FilePath) | |
sb.WriteString(")") | |
} | |
return sb.String() | |
} | |
func (f *file) CopyAttachments(fileSys fs.FS, toDir string) error { | |
for _, attachment := range f.Attachments { | |
fin, err := fileSys.Open(strings.ReplaceAll(attachment.FilePath, ".jpeg", ".jpg")) | |
if err != nil { | |
return err | |
} | |
defer fin.Close() | |
fout, err := os.Create(path.Join(toDir, attachment.FilePath)) | |
if err != nil { | |
return err | |
} | |
defer fout.Close() | |
_, err = io.Copy(fout, fin) | |
if err != nil { | |
return err | |
} | |
} | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment