mirror of
https://github.com/go-shiori/shiori.git
synced 2025-02-22 23:14:02 +08:00
Add command for opening bookmarks
This commit is contained in:
parent
cd5a74a123
commit
7b977b3f75
4 changed files with 176 additions and 0 deletions
111
cmd/open.go
Normal file
111
cmd/open.go
Normal file
|
@ -0,0 +1,111 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
openCmd = &cobra.Command{
|
||||
Use: "open [indices]",
|
||||
Short: "Open the saved bookmarks.",
|
||||
Long: "Open bookmarks in browser. " +
|
||||
"Accepts space-separated list of indices (e.g. 5 6 23 4 110 45), hyphenated range (e.g. 100-200) or both (e.g. 1-3 7 9). " +
|
||||
"If no arguments, ALL bookmarks will be opened.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Read flags
|
||||
cacheOnly, _ := cmd.Flags().GetBool("cache")
|
||||
trimSpace, _ := cmd.Flags().GetBool("trim-space")
|
||||
skipConfirmation, _ := cmd.Flags().GetBool("yes")
|
||||
|
||||
// If no arguments, confirm to user
|
||||
if len(args) == 0 && !skipConfirmation {
|
||||
confirmOpen := ""
|
||||
fmt.Print("Open ALL bookmarks? (y/n): ")
|
||||
fmt.Scanln(&confirmOpen)
|
||||
|
||||
if confirmOpen != "y" {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if cacheOnly {
|
||||
openBookmarksCache(trimSpace, args...)
|
||||
} else {
|
||||
openBookmarks(args...)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
openCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt and open ALL bookmarks")
|
||||
openCmd.Flags().BoolP("cache", "c", false, "Open the bookmark's cache in text-only mode")
|
||||
openCmd.Flags().Bool("trim-space", false, "Trim all spaces and newlines from the bookmark's cache")
|
||||
rootCmd.AddCommand(openCmd)
|
||||
}
|
||||
|
||||
func openBookmarks(args ...string) {
|
||||
// Read bookmarks from database
|
||||
bookmarks, err := DB.GetBookmarks(args...)
|
||||
if err != nil {
|
||||
cError.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(bookmarks) == 0 {
|
||||
if len(args) > 0 {
|
||||
cError.Println("No matching index found")
|
||||
} else {
|
||||
cError.Println("No saved bookmarks yet")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Open in browser
|
||||
for _, book := range bookmarks {
|
||||
exec.Command("xdg-open", book.URL).Run()
|
||||
if err != nil {
|
||||
cError.Printf("Failed to open %s: %v\n", book.URL, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func openBookmarksCache(trimSpace bool, args ...string) {
|
||||
// Read bookmark content from database
|
||||
bookmarks, err := DB.GetBookmarksContent(args...)
|
||||
if err != nil {
|
||||
cError.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Get terminal width
|
||||
termWidth := getTerminalWidth()
|
||||
if termWidth < 50 {
|
||||
termWidth = 50
|
||||
}
|
||||
|
||||
// Show bookmarks content
|
||||
for _, book := range bookmarks {
|
||||
if trimSpace {
|
||||
words := strings.Fields(book.Content)
|
||||
book.Content = strings.Join(words, " ")
|
||||
}
|
||||
|
||||
cIndex.Printf("%d. ", book.ID)
|
||||
cTitle.Println(book.Title)
|
||||
fmt.Println()
|
||||
|
||||
if book.Content == "" {
|
||||
cError.Println("This bookmark doesn't have any cached content")
|
||||
} else {
|
||||
fmt.Println(book.Content)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
cSymbol.Println(strings.Repeat("-", termWidth))
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@ package cmd
|
|||
|
||||
import (
|
||||
"github.com/fatih/color"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -14,3 +16,8 @@ var (
|
|||
cExcerpt = color.New(color.FgHiWhite)
|
||||
cTag = color.New(color.FgHiBlue)
|
||||
)
|
||||
|
||||
func getTerminalWidth() int {
|
||||
width, _, _ := terminal.GetSize(int(os.Stdin.Fd()))
|
||||
return width
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ type Database interface {
|
|||
GetBookmarks(indices ...string) ([]model.Bookmark, error)
|
||||
DeleteBookmarks(indices ...string) ([]int, []int, error)
|
||||
SearchBookmarks(keyword string, tags ...string) ([]model.Bookmark, error)
|
||||
GetBookmarksContent(indices ...string) ([]model.Bookmark, error)
|
||||
}
|
||||
|
||||
func checkError(err error) {
|
||||
|
|
|
@ -429,3 +429,60 @@ func (db *SQLiteDatabase) SearchBookmarks(keyword string, tags ...string) ([]mod
|
|||
|
||||
return bookmarks, nil
|
||||
}
|
||||
|
||||
func (db *SQLiteDatabase) GetBookmarksContent(indices ...string) ([]model.Bookmark, error) {
|
||||
// Convert list of index to int
|
||||
listIndex := []int{}
|
||||
errInvalidIndex := fmt.Errorf("Index is not valid")
|
||||
|
||||
for _, strIndex := range indices {
|
||||
if strings.Contains(strIndex, "-") {
|
||||
parts := strings.Split(strIndex, "-")
|
||||
if len(parts) != 2 {
|
||||
return nil, errInvalidIndex
|
||||
}
|
||||
|
||||
minIndex, errMin := strconv.Atoi(parts[0])
|
||||
maxIndex, errMax := strconv.Atoi(parts[1])
|
||||
if errMin != nil || errMax != nil || minIndex < 1 || minIndex > maxIndex {
|
||||
return nil, errInvalidIndex
|
||||
}
|
||||
|
||||
for i := minIndex; i <= maxIndex; i++ {
|
||||
listIndex = append(listIndex, i)
|
||||
}
|
||||
} else {
|
||||
index, err := strconv.Atoi(strIndex)
|
||||
if err != nil || index < 1 {
|
||||
return nil, errInvalidIndex
|
||||
}
|
||||
|
||||
listIndex = append(listIndex, index)
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare where clause
|
||||
args := []interface{}{}
|
||||
whereClause := " WHERE 1"
|
||||
|
||||
if len(listIndex) > 0 {
|
||||
whereClause = " WHERE docid IN ("
|
||||
for _, idx := range listIndex {
|
||||
args = append(args, idx)
|
||||
whereClause += "?,"
|
||||
}
|
||||
|
||||
whereClause = whereClause[:len(whereClause)-1]
|
||||
whereClause += ")"
|
||||
}
|
||||
|
||||
bookmarks := []model.Bookmark{}
|
||||
err := db.Select(&bookmarks,
|
||||
`SELECT docid id, title, content, html
|
||||
FROM bookmark_content`+whereClause, args...)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bookmarks, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue