-
Notifications
You must be signed in to change notification settings - Fork 538
/
import.go
145 lines (120 loc) · 3.21 KB
/
import.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package cmd
import (
"fmt"
"os"
"strings"
"github.com/PuerkitoBio/goquery"
"github.com/go-shiori/shiori/internal/core"
"github.com/go-shiori/shiori/internal/model"
"github.com/spf13/cobra"
)
func importCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "import source-file",
Short: "Import bookmarks from HTML file in Netscape Bookmark format",
Args: cobra.ExactArgs(1),
Run: importHandler,
}
cmd.Flags().BoolP("generate-tag", "t", false, "Auto generate tag from bookmark's category")
return cmd
}
func importHandler(cmd *cobra.Command, args []string) {
// Parse flags
generateTag := cmd.Flags().Changed("generate-tag")
// If user doesn't specify, ask if tag need to be generated
if !generateTag {
var submit string
fmt.Print("Add parents folder as tag? (y/N): ")
fmt.Scanln(&submit)
generateTag = submit == "y"
}
// Prepare bookmark's ID
bookID, err := db.CreateNewID(cmd.Context(), "bookmark")
if err != nil {
cError.Printf("Failed to create ID: %v\n", err)
os.Exit(1)
}
// Open bookmark's file
srcFile, err := os.Open(args[0])
if err != nil {
cError.Printf("Failed to open %s: %v\n", args[0], err)
os.Exit(1)
}
defer srcFile.Close()
// Parse bookmark's file
bookmarks := []model.Bookmark{}
mapURL := make(map[string]struct{})
doc, err := goquery.NewDocumentFromReader(srcFile)
if err != nil {
cError.Printf("Failed to parse bookmark: %v\n", err)
os.Exit(1)
}
doc.Find("dt>a").Each(func(_ int, a *goquery.Selection) {
// Get related elements
dt := a.Parent()
dl := dt.Parent()
h3 := dl.Parent().Find("h3").First()
// Get metadata
title := a.Text()
url, _ := a.Attr("href")
strTags, _ := a.Attr("tags")
// Clean up URL
var err error
url, err = core.RemoveUTMParams(url)
if err != nil {
cError.Printf("Skip %s: URL is not valid\n", url)
return
}
// Make sure title is valid Utf-8
title = validateTitle(title, url)
// Check if the URL already exist before, both in bookmark
// file or in database
if _, exist := mapURL[url]; exist {
cError.Printf("Skip %s: URL already exists\n", url)
return
}
_, exist, err := db.GetBookmark(cmd.Context(), 0, url)
if err != nil {
cError.Printf("Skip %s: Get Bookmark fail, %v", url, err)
return
}
if exist {
cError.Printf("Skip %s: URL already exists\n", url)
mapURL[url] = struct{}{}
return
}
// Get bookmark tags
tags := []model.Tag{}
for _, strTag := range strings.Split(strTags, ",") {
strTag = normalizeSpace(strTag)
if strTag != "" {
tags = append(tags, model.Tag{Name: strTag})
}
}
// Get category name for this bookmark
// and add it as tags (if necessary)
category := normalizeSpace(h3.Text())
if category != "" && generateTag {
tags = append(tags, model.Tag{Name: category})
}
// Add item to list
bookmark := model.Bookmark{
ID: bookID,
URL: url,
Title: title,
Tags: tags,
}
bookID++
mapURL[url] = struct{}{}
bookmarks = append(bookmarks, bookmark)
})
// Save bookmark to database
bookmarks, err = db.SaveBookmarks(cmd.Context(), bookmarks...)
if err != nil {
cError.Printf("Failed to save bookmarks: %v\n", err)
os.Exit(1)
}
// Print imported bookmark
fmt.Println()
printBookmarks(bookmarks...)
}