Skip to content

Commit

Permalink
Merge pull request #24 from nikhil1raghav/cobra
Browse files Browse the repository at this point in the history
Autoclassify filetype, added cobra for command line options
  • Loading branch information
nikhil1raghav authored Apr 16, 2023
2 parents f9dfae0 + 07e80f2 commit 3e8a628
Show file tree
Hide file tree
Showing 89 changed files with 12,227 additions and 143 deletions.
72 changes: 52 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@

## Documentation

`kindle-send` is a command line utility to send files and webpages to your kindle via e-mail.
`kindle-send` is a CLI tool to send files and webpages to your e-reader via e-mail.

Webpages are optimized for viewing on kindle
Webpages are optimized for viewing on e-reader


<p align = "center">
Expand All @@ -37,8 +37,7 @@ Webpages are optimized for viewing on kindle
---


An epub is created from a url, then mailed to the kindle. Amazon converts that epub into azw3 for viewing on kindle.

An epub is created from the url, then mailed to the kindle. Amazon converts that epub into azw3 for viewing on kindle.
So you can use kindle-send, even if you're using a different ereader like Kobo and Remarkable if it supports pushing ebooks via email.


Expand All @@ -49,10 +48,6 @@ So you can use kindle-send, even if you're using a different ereader like Kobo a

To run kindle-send you just need the compiled binary, no other dependency is required.

As this was not the case with the older [python version](https://github.com/nikhil1raghav/kindle-send/tree/python) which required percollate, calibre etc.



#### Brew

Kindle-send can be installed via brew
Expand All @@ -79,7 +74,7 @@ go install github.com/nikhil1raghav/kindle-send@latest
For the first time when you run `kindle-send`, you need to answer some questions to create a configuration file, which has options like sender, receiver, password and path to store the generated files.


If you're using gmail to send mails to kindle, please consider creating an [app password](https://support.google.com/mail/answer/185833?hl=en-GB) and then using it.
If you're using gmail to send mails to kindle, consider creating an [app password](https://support.google.com/mail/answer/185833?hl=en-GB) and then using it.


---
Expand All @@ -93,12 +88,12 @@ __1. Send a file__
Using `kindle-send` to mail an already existing file.

```sh
kindle-send --file <path-to-file>
kindle-send send Jane-eyre-Autobiography.epub
```


<p align="center">
<img width="100%" src="assets/file-send.svg">
<img width="100%" src="assets/sendfile-new.svg">
</p>


Expand All @@ -108,45 +103,79 @@ Quickly send a webpage to kindle


```sh
kindle-send --url <link-to-a-webpage>
kindle-send send http://paulgraham.com/hwh.html
```

<p align="center">
<img width="100%" src="assets/kindle-send-window.svg">
<img width="100%" src="assets/sendurl-new.svg">
</p>


__3. Multiple webpages combined in a single volume__


Create a text file with new line separated links of webpages and then pass it as link file to `--linkfile` option
Create a text file with new line separated links of webpages and then all the webpages mentioned in the file will be bound in a single ebook as chapters and sent to ereader.



```sh
kindle-send --linkfile <path-to-url-file>
kindle-send send links.txt
```

<p align="center">
<img width="100%" src="assets/linkfile.svg">
<img width="100%" src="assets/send-link-file-new.svg">
</p>



__4. Send Multiple files at once__

You can send multiple files or links at once.

`kindle-send` auto detects the type of file and takes required action.


Each argument is sent as a separate file.


For example, the command below will send an html page (converted to ebook), an ebook and a collection of bookmarks post downloading the webpages and creating an ebook from them.


```sh
kindle-send send http://paulgraham.com/hwh.html jane-eyre-autobiography.epub some-links.txt
```



__5. Download but not send__

If you just want to save a webpage for reading later, replace `send` with `download` and the files will be saved in local directory but will not be sent to an ereader.

Example

```sh
kindle-send download https://blog.maxgio.me/posts/linux-scheduler-journey/
```

<p align="center">
<img width="100%" src="assets/download-new.svg">
</p>



### Additional options

Default timeout for mail is 2 minutes, if you get timeout error while sending bigger files. Please increase the timeout using `--mail-timeout <number of seconds>` option
Default timeout for mail is 2 minutes, if you get timeout error while sending bigger files. Increase the timeout using `--mail-timeout <number of seconds>` or `-m` option



Specify the title for the document using `--title` option.
Specify a different configuration file using `--config` or `-c` option. Configuration is stored in home directory as `KindleConfig.json`. You can directly edit it if you want.

Specify a different configuration file using `--config` option. Configuration is stored in home directory as `KindleConfig.json`. You can directly edit it if you want.

When sending a collection of pages if no title is provided, volume takes the title of the first page.

You can always get more information about usage of commands and options by typing `kindle-send help`


---

Expand All @@ -160,7 +189,10 @@ Feel free to create an issue and then working on some feature, so that we don't
- [ ] Weekly RSS feed dump, when combined with `cron`
- [ ] Better CSS & formatting for epub
- [ ] Compressing images before embedding to reduce final file size
- [ ] Simple UI form driven by CLI. Something like `kindle-send dashboard`.
- [x] Auto detect file type
- [x] Option to download but not send the files
- [x] Remove dependency on percollate and calibre
- [x] Make installation easier
- [x] Make installation easier, add brew and other package managers.


2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.3-rc-2
2.0.0-rc-1
86 changes: 86 additions & 0 deletions assets/download-new.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
100 changes: 100 additions & 0 deletions assets/send-link-file-new.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 90 additions & 0 deletions assets/sendfile-new.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions assets/sendurl-new.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 71 additions & 0 deletions classifier/classifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package classifier

import (
"os"
"path/filepath"
"strings"

"github.com/nikhil1raghav/kindle-send/types"
)

func isUrl(u string) bool {
for _, proto := range []string{"http://", "https://"} {
if strings.HasPrefix(u, proto) {
return true
}
}
return false
}

func isUrlFile(u string) bool {
file, err := os.Open(u)
if err != nil {
return false
}
defer file.Close()
buf := make([]byte, 1024)
n, _ := file.Read(buf)
content := string(buf[:n])
lines := strings.Split(content, "\n")
for _, line := range lines {
line = strings.Trim(line, " ")
if len(line) == 0 {
continue
}
if !strings.HasPrefix(line, "http") {
return false
}
}
return true
}

func isBook(u string) bool {
extension := filepath.Ext(u)
// does file exist
_, err := os.Stat(u)
if err != nil {
return false
}
for _, ext := range []string{".mobi", ".pdf", ".epub", ".azw3", ".txt"} {
if extension == ext {
return true
}
}
return false
}

func Classify(args []string) []types.Request {
var requests []types.Request
for _, arg := range args {
if isUrl(arg) {
requests = append(requests, types.NewRequest(arg, types.TypeUrl, nil))
} else if isUrlFile(arg) {
requests = append(requests, types.NewRequest(arg, types.TypeUrlFile, nil))
} else if isBook(arg) {
requests = append(requests, types.NewRequest(arg, types.TypeFile, nil))
}
}

return requests

}
58 changes: 58 additions & 0 deletions cmd/download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package cmd

import (
"os"

"github.com/lithammer/dedent"
"github.com/nikhil1raghav/kindle-send/classifier"
"github.com/nikhil1raghav/kindle-send/config"
"github.com/nikhil1raghav/kindle-send/handler"
"github.com/nikhil1raghav/kindle-send/util"
"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(downloadCmd)
}

var (
helpDownload = `Downloads the webpage or collection of webpages from given arguments
that can be a standalone link or a text file containing multiple links.
Supports multiple arguments. Each argument is downloaded as a separate file.`

exampleDownload = dedent.Dedent(`
# Download a single webpage
kindle-send download "http://paulgraham.com/alien.html"
# Download multiple webpages
kindle-send download "http://paulgraham.com/alien.html" "http://paulgraham.com/hwh.html"
# Download webpage and collection of webpages
kindle-send download "http://paulgraham.com/alien.html" links.txt`,
)
)

var downloadCmd = &cobra.Command{
Use: "download [LINK1] [LINK2] [FILE1] [FILE2]",
Short: "Download the webpage as ebook and save locally",
Long: helpDownload,
Example: exampleDownload,
Run: func(cmd *cobra.Command, args []string) {
configPath, _ := cmd.Flags().GetString("config")
_, err := config.Load(configPath)
if err != nil {
util.Red.Println(err)
return
}

downloadRequests := classifier.Classify(args)
downloadedRequests := handler.Queue(downloadRequests)

util.CyanBold.Printf("Downloaded %d files :\n", len(downloadRequests))
for idx, req := range downloadedRequests {
fileInfo, _ := os.Stat(req.Path)
util.Cyan.Printf("%d. %s\n", idx+1, fileInfo.Name())
}

},
}
45 changes: 45 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package cmd

import (
"fmt"
"os"

"github.com/nikhil1raghav/kindle-send/config"
"github.com/nikhil1raghav/kindle-send/util"
"github.com/spf13/cobra"
)

func init() {
var configPath string
configPath, err := config.DefaultConfigPath()
if err != nil {
util.Red.Println("Error setting default config path: ", err)
os.Exit(1)
}
rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", configPath, "Path to config file")

}

var rootCmd = &cobra.Command{
Use: "kindle-send",
Short: "kindle-send sends documents, webpages and books to your ereader",
Long: `kindle-send is a CLI tool to send file (books/documents) and webpages to your ereader
It parses the webpage, optimizes it for reading on ereader, and then converts
into an ebook. Then it emails the ebook to the ereader.
Complete documentation is available at https://github.com/nikhil1raghav/kindle-send`,
Run: func(cmd *cobra.Command, args []string) {
configPath, _ := cmd.Flags().GetString("config")
_, err := config.Load(configPath)
if err != nil {
util.Red.Println(err)
return
}
},
}

func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
62 changes: 62 additions & 0 deletions cmd/send.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package cmd

import (
"github.com/lithammer/dedent"
"github.com/nikhil1raghav/kindle-send/classifier"
"github.com/nikhil1raghav/kindle-send/config"
"github.com/nikhil1raghav/kindle-send/handler"
"github.com/nikhil1raghav/kindle-send/util"
"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(sendCmd)
}

var (
helpLong = `Sends the files to ereader. If a link or a file containing links is given
it will first download the webpage, convert into ebook and then send.
Each argument is sent as a separate file.
kindle-send auto detects if argument is a link, collection of links or an ebook.`

helpExample = dedent.Dedent(`
# Send a single webpage
kindle-send send "http://paulgraham.com/alien.html"
# Send multiple webpages
kindle-send send "http://paulgraham.com/alien.html" "http://paulgraham.com/hwh.html"
# Send webpage, collection of webpages and an ebook
kindle-send download "http://paulgraham.com/alien.html" links.txt "Some Book.epub"`,
)
)

func init() {
sendCmd.PersistentFlags().IntP("mail-timeout", "m", 120, "Mail timeout in seconds, increase it if sending lot of files")
}

var sendCmd = &cobra.Command{
Use: "send [LINK1] [LINK2] [FILE1] [FILE2]",
Short: "Send the files, links, documents to ereader",
Long: helpLong,
Example: helpExample,
Run: func(cmd *cobra.Command, args []string) {
configPath, _ := cmd.Flags().GetString("config")
_, err := config.Load(configPath)
if err != nil {
util.Red.Println(err)
return
}

downloadRequests := classifier.Classify(args)
downloadedRequests := handler.Queue(downloadRequests)

timeout, err := cmd.Flags().GetInt("mail-timeout")
if err != nil {
timeout = 0
}

handler.Mail(downloadedRequests, timeout)

},
}
Loading

0 comments on commit 3e8a628

Please sign in to comment.