Add import command

This commit is contained in:
Radhi Fadlillah 2018-02-25 16:04:12 +07:00
parent b0796d3ed3
commit 0940fd66ef
6 changed files with 177 additions and 58 deletions

View file

@ -5,7 +5,7 @@ import (
"github.com/RadhiFadlillah/shiori/model"
"github.com/spf13/cobra"
"html/template"
"os"
"strings"
"time"
)
@ -22,14 +22,26 @@ var (
tags, _ := cmd.Flags().GetStringSlice("tags")
offline, _ := cmd.Flags().GetBool("offline")
// Save new bookmark
bookmark, err := addBookmark(url, title, excerpt, tags, offline)
if err != nil {
cError.Println(err)
os.Exit(1)
// Create bookmark item
bookmark := model.Bookmark{
URL: url,
Title: normalizeSpace(title),
Excerpt: normalizeSpace(excerpt),
}
printBookmark(bookmark)
bookmark.Tags = make([]model.Tag, len(tags))
for i, tag := range tags {
bookmark.Tags[i].Name = tag
}
// Save new bookmark
result, err := addBookmark(bookmark, offline)
if err != nil {
cError.Println(err)
return
}
printBookmark(result)
},
}
)
@ -42,53 +54,42 @@ func init() {
rootCmd.AddCommand(addCmd)
}
func addBookmark(url, title, excerpt string, tags []string, offline bool) (book model.Bookmark, err error) {
func addBookmark(base model.Bookmark, offline bool) (book model.Bookmark, err error) {
// Prepare initial result
book = base
// Fetch data from internet
article := readability.Article{}
if !offline {
article, err = readability.Parse(url, 10*time.Second)
article, err := readability.Parse(book.URL, 10*time.Second)
if err != nil {
cError.Println("Failed to fetch article from internet:", err)
article.URL = url
article.Meta.Title = "Untitled"
if book.Title == "" {
book.Title = "Untitled"
}
} else {
book.URL = article.URL
book.ImageURL = article.Meta.Image
book.Author = article.Meta.Author
book.MinReadTime = article.Meta.MinReadTime
book.MaxReadTime = article.Meta.MaxReadTime
book.Content = article.Content
book.HTML = template.HTML(article.RawContent)
if book.Title == "" {
book.Title = article.Meta.Title
}
if book.Excerpt == "" {
book.Excerpt = article.Meta.Excerpt
}
}
}
// Prepare bookmark
bookmark := model.Bookmark{
URL: article.URL,
Title: article.Meta.Title,
ImageURL: article.Meta.Image,
Excerpt: article.Meta.Excerpt,
Author: article.Meta.Author,
MinReadTime: article.Meta.MinReadTime,
MaxReadTime: article.Meta.MaxReadTime,
Content: article.Content,
HTML: template.HTML(article.RawContent),
}
bookTags := make([]model.Tag, len(tags))
for i, tag := range tags {
bookTags[i].Name = tag
}
bookmark.Tags = bookTags
// Set custom value
if title != "" {
bookmark.Title = title
}
if excerpt != "" {
bookmark.Excerpt = excerpt
}
// Save to database
bookmark.ID, err = DB.CreateBookmark(bookmark)
if err != nil {
return book, err
}
bookmark.Modified = time.Now().UTC().Format("2006-01-02 15:04:05")
return bookmark, nil
book.ID, err = DB.CreateBookmark(book)
return book, err
}
func normalizeSpace(str string) string {
return strings.Join(strings.Fields(str), " ")
}

113
cmd/import.go Normal file
View file

@ -0,0 +1,113 @@
package cmd
import (
"fmt"
"github.com/PuerkitoBio/goquery"
"github.com/RadhiFadlillah/shiori/model"
"github.com/spf13/cobra"
"os"
"strconv"
"strings"
"time"
)
var (
importCmd = &cobra.Command{
Use: "import file",
Short: "Import bookmarks from HTML file in Firefox format.",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
generateTag := cmd.Flags().Changed("generate-tag")
if !generateTag {
var submitGenerateTag string
fmt.Print("Add parents folder as tag? (y/n): ")
fmt.Scanln(&submitGenerateTag)
generateTag = submitGenerateTag == "y"
}
err := importBookmarks(args[0], generateTag)
if err != nil {
cError.Println(err)
return
}
},
}
)
func init() {
importCmd.Flags().BoolP("generate-tag", "t", false, "Auto generate tag from bookmark's category")
rootCmd.AddCommand(importCmd)
}
func importBookmarks(pth string, generateTag bool) error {
// Open file
srcFile, err := os.Open(pth)
if err != nil {
return err
}
defer srcFile.Close()
// Parse file
doc, err := goquery.NewDocumentFromReader(srcFile)
if err != nil {
return err
}
// Fetch each bookmark categories
bookmarks := []model.Bookmark{}
doc.Find("body>dl>dt").Each(func(_ int, el *goquery.Selection) {
// Create category title
category := el.Find("h3").First().Text()
category = normalizeSpace(category)
category = strings.ToLower(category)
category = strings.Replace(category, " ", "-", -1)
// Fetch all link in this categories
el.Find("dl>dt").Each(func(_ int, dt *goquery.Selection) {
// Get bookmark link
a := dt.Find("a").First()
title := a.Text()
url, _ := a.Attr("href")
strModified, _ := a.Attr("last_modified")
intModified, _ := strconv.ParseInt(strModified, 10, 64)
modified := time.Unix(intModified, 0)
// Get bookmark excerpt
excerpt := ""
if nxt := dt.Next(); nxt.Is("dd") {
excerpt = nxt.Text()
}
// Create bookmark item
bookmark := model.Bookmark{
URL: url,
Title: normalizeSpace(title),
Excerpt: normalizeSpace(excerpt),
Modified: modified.Format("2006-01-02 15:04:05"),
Tags: []model.Tag{},
}
if generateTag {
bookmark.Tags = []model.Tag{
{Name: category},
}
}
bookmarks = append(bookmarks, bookmark)
})
})
// Save bookmarks to database
for _, book := range bookmarks {
result, err := addBookmark(book, true)
if err != nil {
cError.Printf("URL %s already exists\n\n", book.URL)
continue
}
printBookmark(result)
}
return nil
}

View file

@ -218,12 +218,7 @@ func apiInsertBookmarks(w http.ResponseWriter, r *http.Request, ps httprouter.Pa
checkError(err)
// Save bookmark
tags := make([]string, len(request.Tags))
for i, tag := range request.Tags {
tags[i] = tag.Name
}
book, err := addBookmark(request.URL, request.Title, request.Excerpt, tags, false)
book, err := addBookmark(request, false)
checkError(err)
// Return new saved result

View file

@ -9,6 +9,7 @@ import (
"sort"
"strconv"
"strings"
"time"
)
// SQLiteDatabase is implementation of Database interface for connecting to SQLite3 database.
@ -87,6 +88,10 @@ func (db *SQLiteDatabase) CreateBookmark(bookmark model.Bookmark) (bookmarkID in
return -1, fmt.Errorf("Title must not empty")
}
if bookmark.Modified == "" {
bookmark.Modified = time.Now().UTC().Format("2006-01-02 15:04:05")
}
// Prepare transaction
tx, err := db.Beginx()
if err != nil {
@ -107,15 +112,16 @@ func (db *SQLiteDatabase) CreateBookmark(bookmark model.Bookmark) (bookmarkID in
// Save article to database
res := tx.MustExec(`INSERT INTO bookmark (
url, title, image_url, excerpt, author,
min_read_time, max_read_time)
VALUES(?, ?, ?, ?, ?, ?, ?)`,
min_read_time, max_read_time, modified)
VALUES(?, ?, ?, ?, ?, ?, ?, ?)`,
bookmark.URL,
bookmark.Title,
bookmark.ImageURL,
bookmark.Excerpt,
bookmark.Author,
bookmark.MinReadTime,
bookmark.MaxReadTime)
bookmark.MaxReadTime,
bookmark.Modified)
// Get last inserted ID
bookmarkID, err = res.LastInsertId()

File diff suppressed because one or more lines are too long

View file

@ -582,6 +582,10 @@
border-top: 1px solid @border;
visibility: hidden;
margin-top: 16px;
&:nth-child(3) {
border-top: 0;
margin-top: 0;
}
a {
cursor: pointer;
display: block;