Skip to content

Commit 9b0d9d9

Browse files
author
czyt
committed
first init
1 parent bd6ed78 commit 9b0d9d9

File tree

9 files changed

+189
-1
lines changed

9 files changed

+189
-1
lines changed

.idea/.gitignore

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/enex.iml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,16 @@
11
# go-enex
2-
evernote .enex file parser
2+
evernote .enex file parser in go
3+
4+
## Example
5+
6+
## TODO
7+
+ [ ] en-crypt
8+
+ [ ] en-todo
9+
+ [ ] en-media
10+
11+
## Refer
12+
+ [evernote2md](https://github.com/wormi4ok/evernote2md/blob/master/encoding/enex/enex.go)
13+
+ [go-enex](https://github.com/macrat/go-enex)
14+
+ http://xml.evernote.com/pub/enml2.dtd
15+
+ http://xml.evernote.com/pub/evernote-export2.dtd
16+

enex.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package enex
2+
3+
import (
4+
"bytes"
5+
"encoding/xml"
6+
"errors"
7+
"fmt"
8+
"io"
9+
"regexp"
10+
)
11+
12+
type (
13+
// Export represents Evernote enex file structure
14+
Export struct {
15+
XMLName xml.Name `xml:"en-export"`
16+
Date string `xml:"export-date,attr"`
17+
Notes []Note `xml:"note"`
18+
}
19+
20+
// Note is one note in Evernote
21+
Note struct {
22+
XMLName xml.Name `xml:"note"`
23+
Title string `xml:"title"`
24+
Content []byte `xml:"content"`
25+
Updated string `xml:"updated"`
26+
Created string `xml:"created"`
27+
Tags []string `xml:"tag"`
28+
Attributes NoteAttributes `xml:"note-attributes"`
29+
Resources []Resource `xml:"resource"`
30+
}
31+
32+
// NoteAttributes contain the note metadata
33+
NoteAttributes struct {
34+
Source string `xml:"source"`
35+
SourceApplication string `xml:"source-application"`
36+
Latitude string `xml:"latitude"`
37+
Longitude string `xml:"longitude"`
38+
Altitude string `xml:"altitude"`
39+
Author string `xml:"author"`
40+
SourceUrl string `xml:"source-url"`
41+
}
42+
43+
// Resource embedded in the note
44+
Resource struct {
45+
ID string
46+
Type string
47+
Data Data `xml:"data"`
48+
Mime string `xml:"mime"`
49+
Width int `xml:"width"`
50+
Height int `xml:"height"`
51+
Attributes Attributes `xml:"resource-attributes"`
52+
Recognition []byte `xml:"recognition"`
53+
}
54+
55+
// Attributes of the resource
56+
Attributes struct {
57+
Timestamp string `xml:"timestamp"`
58+
Filename string `xml:"file-name"`
59+
SourceUrl string `xml:"source-url"`
60+
}
61+
// Recognition for the resource
62+
Recognition struct {
63+
XMLName xml.Name `xml:"recoIndex"`
64+
ObjID string `xml:"objID,attr"`
65+
ObjType string `xml:"objType,attr"`
66+
}
67+
68+
// Data object in base64
69+
Data struct {
70+
XMLName xml.Name `xml:"data"`
71+
Encoding string `xml:"encoding,attr"`
72+
Content []byte `xml:",innerxml"`
73+
}
74+
75+
// Content of Evernote Notes
76+
Content struct {
77+
Text []byte `xml:",innerxml"`
78+
}
79+
)
80+
81+
var hashRe = regexp.MustCompile(`\b[0-9a-f]{32}\b`)
82+
83+
// Decode will return an Export from evernote
84+
func Decode(data io.Reader) (*Export, error) {
85+
var e Export
86+
err := newDecoder(data).Decode(&e)
87+
88+
for i := range e.Notes {
89+
var c Content
90+
var reader = bytes.NewReader(e.Notes[i].Content)
91+
92+
if err := newDecoder(reader).Decode(&c); err != nil {
93+
// EOF is a known case when the content is empty
94+
if !errors.Is(err, io.EOF) {
95+
return nil, fmt.Errorf("decoding note %s: %w", e.Notes[i].Title, err)
96+
}
97+
}
98+
e.Notes[i].Content = c.Text
99+
100+
for j := range e.Notes[i].Resources {
101+
if res := e.Notes[i].Resources[j]; len(res.Recognition) == 0 {
102+
hash := hashRe.FindString(res.Attributes.SourceUrl)
103+
if len(hash) > 0 {
104+
e.Notes[i].Resources[j].ID = hash
105+
}
106+
continue
107+
}
108+
var rec Recognition
109+
decoder := newDecoder(bytes.NewReader(e.Notes[i].Resources[j].Recognition))
110+
err = decoder.Decode(&rec)
111+
if err != nil {
112+
return nil, fmt.Errorf("decoding resource %s: %w", e.Notes[i].Resources[j].Attributes.Filename, err)
113+
}
114+
e.Notes[i].Resources[j].ID = rec.ObjID
115+
e.Notes[i].Resources[j].Type = rec.ObjType
116+
}
117+
}
118+
119+
return &e, err
120+
}
121+
122+
func newDecoder(r io.Reader) *xml.Decoder {
123+
d := xml.NewDecoder(r)
124+
d.Strict = false
125+
return d
126+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/czyt/enex
2+
3+
go 1.19

testdata/en-crypt.enex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export2.dtd">
3+
<en-export export-date="20220920T151222Z" application="Evernote/Windows" version="6.x">
4+
<note><title>crypt data pwd:aaa</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
5+
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
6+
7+
<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>

testdata/todolist.enex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export2.dtd">
3+
<en-export export-date="20220920T151621Z" application="Evernote/Windows" version="6.x">
4+
<note><title>todolist</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
5+
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
6+
7+
<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 commit comments

Comments
 (0)