Skip to content

Commit

Permalink
first init
Browse files Browse the repository at this point in the history
  • Loading branch information
czyt committed Sep 20, 2022
1 parent bd6ed78 commit 9b0d9d9
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 1 deletion.
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/enex.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
# go-enex
evernote .enex file parser
evernote .enex file parser in go

## Example

## TODO
+ [ ] en-crypt
+ [ ] en-todo
+ [ ] en-media

## Refer
+ [evernote2md](https://github.com/wormi4ok/evernote2md/blob/master/encoding/enex/enex.go)
+ [go-enex](https://github.com/macrat/go-enex)
+ http://xml.evernote.com/pub/enml2.dtd
+ http://xml.evernote.com/pub/evernote-export2.dtd

126 changes: 126 additions & 0 deletions enex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package enex

import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"io"
"regexp"
)

type (
// Export represents Evernote enex file structure
Export struct {
XMLName xml.Name `xml:"en-export"`
Date string `xml:"export-date,attr"`
Notes []Note `xml:"note"`
}

// Note is one note in Evernote
Note struct {
XMLName xml.Name `xml:"note"`
Title string `xml:"title"`
Content []byte `xml:"content"`
Updated string `xml:"updated"`
Created string `xml:"created"`
Tags []string `xml:"tag"`
Attributes NoteAttributes `xml:"note-attributes"`
Resources []Resource `xml:"resource"`
}

// NoteAttributes contain the note metadata
NoteAttributes struct {
Source string `xml:"source"`
SourceApplication string `xml:"source-application"`
Latitude string `xml:"latitude"`
Longitude string `xml:"longitude"`
Altitude string `xml:"altitude"`
Author string `xml:"author"`
SourceUrl string `xml:"source-url"`
}

// Resource embedded in the note
Resource struct {
ID string
Type string
Data Data `xml:"data"`
Mime string `xml:"mime"`
Width int `xml:"width"`
Height int `xml:"height"`
Attributes Attributes `xml:"resource-attributes"`
Recognition []byte `xml:"recognition"`
}

// Attributes of the resource
Attributes struct {
Timestamp string `xml:"timestamp"`
Filename string `xml:"file-name"`
SourceUrl string `xml:"source-url"`
}
// Recognition for the resource
Recognition struct {
XMLName xml.Name `xml:"recoIndex"`
ObjID string `xml:"objID,attr"`
ObjType string `xml:"objType,attr"`
}

// Data object in base64
Data struct {
XMLName xml.Name `xml:"data"`
Encoding string `xml:"encoding,attr"`
Content []byte `xml:",innerxml"`
}

// Content of Evernote Notes
Content struct {
Text []byte `xml:",innerxml"`
}
)

var hashRe = regexp.MustCompile(`\b[0-9a-f]{32}\b`)

// Decode will return an Export from evernote
func Decode(data io.Reader) (*Export, error) {
var e Export
err := newDecoder(data).Decode(&e)

for i := range e.Notes {
var c Content
var reader = bytes.NewReader(e.Notes[i].Content)

if err := newDecoder(reader).Decode(&c); err != nil {
// EOF is a known case when the content is empty
if !errors.Is(err, io.EOF) {
return nil, fmt.Errorf("decoding note %s: %w", e.Notes[i].Title, err)
}
}
e.Notes[i].Content = c.Text

for j := range e.Notes[i].Resources {
if res := e.Notes[i].Resources[j]; len(res.Recognition) == 0 {
hash := hashRe.FindString(res.Attributes.SourceUrl)
if len(hash) > 0 {
e.Notes[i].Resources[j].ID = hash
}
continue
}
var rec Recognition
decoder := newDecoder(bytes.NewReader(e.Notes[i].Resources[j].Recognition))
err = decoder.Decode(&rec)
if err != nil {
return nil, fmt.Errorf("decoding resource %s: %w", e.Notes[i].Resources[j].Attributes.Filename, err)
}
e.Notes[i].Resources[j].ID = rec.ObjID
e.Notes[i].Resources[j].Type = rec.ObjType
}
}

return &e, err
}

func newDecoder(r io.Reader) *xml.Decoder {
d := xml.NewDecoder(r)
d.Strict = false
return d
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/czyt/enex

go 1.19
7 changes: 7 additions & 0 deletions testdata/en-crypt.enex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export2.dtd">
<en-export export-date="20220920T151222Z" application="Evernote/Windows" version="6.x">
<note><title>crypt data pwd:aaa</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note><div><en-crypt cipher="AES" hint="a*3" length="128">RU5DMFgHgS6gkVaOVGvh9k48uCHyn1E0Md1xRGpoC+w5TPYu6MYWYn4+jkxA4K2oIM5oM5S9pwsdgfv7RdNgR3BmtMecYrrrcbW+RtMRI3NVppPo0rPrhygAFUPQDWk/FrhrXA==</en-crypt><br/></div><div><br/></div></en-note>]]></content><created>20220920T151143Z</created><updated>20220920T151208Z</updated><note-attributes><author>虫子樱桃</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note></en-export>
7 changes: 7 additions & 0 deletions testdata/todolist.enex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export2.dtd">
<en-export export-date="20220920T151621Z" application="Evernote/Windows" version="6.x">
<note><title>todolist</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note><div><en-todo checked="false"/>todo1<br/></div><div><en-todo checked="false"/>todo2</div></en-note>]]></content><created>20220920T151555Z</created><updated>20220920T151609Z</updated><note-attributes><author>虫子樱桃</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note></en-export>

0 comments on commit 9b0d9d9

Please sign in to comment.