Compare commits
377 Commits
v1.4
...
841c342fcc
Author | SHA1 | Date | |
---|---|---|---|
|
841c342fcc | ||
|
5aec3b4dab | ||
|
d787060a24 | ||
|
c1a29418eb | ||
|
17847f999c | ||
|
3adcddc70c | ||
|
e9676491ee | ||
|
1a545bb2a1 | ||
|
1e128a7cd8 | ||
|
5dbb6a710c | ||
|
dadadeb066 | ||
|
c76ff26bd6 | ||
|
50f8648f64 | ||
|
5f82a9e339 | ||
|
3278ba4eac | ||
|
9fc72f8b68 | ||
|
b7b707bd43 | ||
|
7cf27e0fde | ||
|
66f2a973a3 | ||
|
7ecbbff18a | ||
|
850ce195a0 | ||
|
479aebd023 | ||
|
9b178d1fb3 | ||
|
3ab098db5c | ||
|
6d16e93008 | ||
|
98934daee4 | ||
|
259474cae9 | ||
|
1e65a7951b | ||
|
bed5640366 | ||
|
57ea83cf4f | ||
|
219842d723 | ||
|
a96fc101f2 | ||
|
81a77ce0a4 | ||
|
9ed359f964 | ||
|
bc18557820 | ||
|
7d99edab8d | ||
|
32ca121520 | ||
|
9f1a0534a3 | ||
|
d2678be96d | ||
|
95ebbb9d13 | ||
|
0f6d4d639d | ||
|
795a5d2cb4 | ||
|
dd5f760606 | ||
|
58d6a46e36 | ||
|
a8d7b86cdc | ||
|
aac3de7ca2 | ||
|
de24659bae | ||
|
632412c10e | ||
|
012b58bbe4 | ||
|
c092842ee4 | ||
|
e4c1d01915 | ||
|
ce07ddea92 | ||
|
bd6322e533 | ||
|
91da774286 | ||
|
e62906e63d | ||
|
56e5625adc | ||
|
1ecf4b0bb4 | ||
|
57d9421c7f | ||
|
a73188944d | ||
|
97904cc0f3 | ||
|
f28f354992 | ||
|
698f5d6d06 | ||
|
b935a1c511 | ||
|
10e6bfa5a0 | ||
|
f030a4075b | ||
|
c9dd977600 | ||
|
c1bcc0c517 | ||
|
2a5692d9a7 | ||
|
a8d160f9b1 | ||
|
286cbff236 | ||
|
fff0870d3b | ||
|
fe22460c07 | ||
|
18f2789a5d | ||
|
7f161a5408 | ||
|
cba3fbc48c | ||
|
5e46f1480e | ||
|
ead253c55f | ||
|
6b8da92cb3 | ||
|
a91f64ce9d | ||
|
e1a6ccf133 | ||
|
d2c034a850 | ||
|
713930decc | ||
|
ee2a825cf0 | ||
|
8e9da86f83 | ||
|
9eb49fd3a7 | ||
|
684bc25b83 | ||
|
8ceab03cd7 | ||
|
34dad4ac8f | ||
|
b40d930f8a | ||
|
d4b34e900e | ||
|
954b549029 | ||
|
fbd0b2310e | ||
|
be7af0ccaf | ||
|
18221ef12d | ||
|
4c0726412b | ||
|
d7253a60b8 | ||
|
2de3ddff08 | ||
|
830248b6ae | ||
|
f8db2ef7ad | ||
|
109caaa889 | ||
|
d0b83babd2 | ||
|
de3decbffd | ||
|
c92229a698 | ||
|
176852b662 | ||
|
52cc8ecbbd | ||
|
e3e9542f1e | ||
|
b78c8bf8bf | ||
|
bff7476b58 | ||
|
05f5785660 | ||
|
cb50aed89a | ||
|
df655aca5e | ||
|
86853a87bf | ||
|
e3109a4384 | ||
|
eee8002d69 | ||
|
92f11f7513 | ||
|
5428e6be3a | ||
|
1ad693f931 | ||
|
c2d88a7e3f | ||
|
3b29d737eb | ||
|
fe178b8fc6 | ||
|
cca742a1c2 | ||
|
c7eddff118 | ||
|
cf30ed249f | ||
|
26b87dee98 | ||
|
77c7f938f1 | ||
|
f98de9a0a5 | ||
|
6fa2b67024 | ||
|
355e5feb62 | ||
|
a7dd707062 | ||
|
4de46a7bc5 | ||
|
2c6fce3322 | ||
|
19ecfcd0bc | ||
|
d575acfe80 | ||
|
d203d38de6 | ||
|
9f01f63613 | ||
|
982c4ebbbc | ||
|
0c5385cef3 | ||
|
58f4e1f6c9 | ||
|
6b7f69d5c0 | ||
|
7aeb458ee5 | ||
|
7cfd3b3238 | ||
|
55262d38fe | ||
|
a45e29feb7 | ||
|
9f5fd3bb4d | ||
|
63f9d55903 | ||
|
8f36ae013e | ||
|
851aa1a136 | ||
|
f38dcfba3b | ||
|
214c7aacfc | ||
|
eb9bfc57e2 | ||
|
c072783c42 | ||
|
9d701678e1 | ||
|
37ed856d8b | ||
|
28f08ad42a | ||
|
da267a56ef | ||
|
16e4cad9ad | ||
|
d13a04898e | ||
|
ff39fbff70 | ||
|
92c6aac49e | ||
|
4ca81f90e9 | ||
|
75e828cb4c | ||
|
883214a740 | ||
|
36e359c881 | ||
|
87b53fb8ec | ||
|
2ae62855cc | ||
|
19889c1457 | ||
|
f9afbac258 | ||
|
e54df07a40 | ||
|
f8455236dc | ||
|
d308bb64c2 | ||
|
077715f6c2 | ||
|
bfe7bfdbd5 | ||
|
1013cd1122 | ||
|
3e57ccc999 | ||
|
5f23f8be89 | ||
|
211b1456c7 | ||
|
3d9c9d03cc | ||
|
1ea8160f7d | ||
|
2c12875199 | ||
|
bb0b575eca | ||
|
e51ccb723e | ||
|
96796702cf | ||
|
fd44c98cd0 | ||
|
c2a28bcadf | ||
|
30e6afb096 | ||
|
882be1dbf6 | ||
|
8764891b80 | ||
|
fbb0dfed47 | ||
|
42b36965c5 | ||
|
e326c7a0fb | ||
|
9fae33f57b | ||
|
a397d2013d | ||
|
f65aadb055 | ||
|
c825f8864f | ||
|
2edf11a36a | ||
|
2df2f41516 | ||
|
614dcc8975 | ||
|
6acf9af887 | ||
|
ecdfcb5017 | ||
|
144fc1606a | ||
|
9919d72be0 | ||
|
9e95f71de8 | ||
|
09bfc47ef0 | ||
|
2e5ccc3158 | ||
|
70481dff73 | ||
|
cc12f27ce3 | ||
|
c36d82636d | ||
|
b123753d65 | ||
|
f590c358d2 | ||
|
fa2fad0ff6 | ||
|
d8aab7acae | ||
|
63ad971890 | ||
|
0828d6782e | ||
|
cf5856bdf7 | ||
|
34edfc0727 | ||
|
a1b1686d3b | ||
|
c5abf8f9d0 | ||
|
9a5af089eb | ||
|
9edd865bf4 | ||
|
e50c7e1a51 | ||
|
8967936fb6 | ||
|
fa92ea16b0 | ||
|
c8d6363677 | ||
|
b082c3e048 | ||
|
82fdb3be6c | ||
|
d7ba203f28 | ||
|
1cba53f7fb | ||
|
0a0db68905 | ||
|
3512350a22 | ||
|
8b2a9d8f20 | ||
|
34b50d388a | ||
|
cd412a4ac5 | ||
|
7fb6271e56 | ||
|
2cd815d9cd | ||
|
0a6e621c02 | ||
|
10c656a3b6 | ||
|
0ea313d945 | ||
|
1f02bde5e1 | ||
|
3e0c784744 | ||
|
528df7fb4a | ||
|
b04e8c1e93 | ||
|
0b8bf50204 | ||
|
f43924c17b | ||
|
0f519b7202 | ||
|
c74eeff790 | ||
|
e7b645a68a | ||
|
fc0bfd29db | ||
|
8950181f21 | ||
|
70e592c979 | ||
|
401668e413 | ||
|
37ddde1765 | ||
|
82586dedff | ||
|
ac36892150 | ||
|
c958ee9116 | ||
|
e5920259b6 | ||
|
8c44d2fc87 | ||
|
332ee0e6b5 | ||
|
3ae17171e2 | ||
|
493a4262b1 | ||
|
485587825c | ||
|
a83d43a5b1 | ||
|
71f81a3802 | ||
|
6481c97645 | ||
|
fa40a79d50 | ||
|
169d579400 | ||
|
430f300140 | ||
|
a9b450db03 | ||
|
89ce8df0e3 | ||
|
aa015b78c0 | ||
|
3ed1b3e612 | ||
|
7fb0d3833e | ||
|
2da616d4ff | ||
|
0b3d7faf9f | ||
|
b3ba912566 | ||
|
36bc84d99a | ||
|
f126247262 | ||
|
b145b00f8e | ||
|
7dbfecdba1 | ||
|
ad693aaf02 | ||
|
fafa6286d4 | ||
|
cc51fe01c2 | ||
|
91deb41d5b | ||
|
2e4082df77 | ||
|
51cbdea31f | ||
|
5335863488 | ||
|
c2e1926741 | ||
|
37a679fc80 | ||
|
1be79d922b | ||
|
6685bce51c | ||
|
fe1a1987bd | ||
|
80402943a1 | ||
|
b40fe94147 | ||
|
e0e6166cdf | ||
|
a2bfd1682b | ||
|
1f393faf79 | ||
|
c469749eaa | ||
|
e0009e4267 | ||
|
24a06faa3c | ||
|
9ede816078 | ||
|
646519e074 | ||
|
454eff0155 | ||
|
ebd7f2929c | ||
|
5b36530f67 | ||
|
c91b439878 | ||
|
7d61f705bf | ||
|
9fa8b8440a | ||
|
9e8837b37d | ||
|
7ca9415322 | ||
|
e78c028d20 | ||
|
cbc75047b8 | ||
|
cc6f6d91e1 | ||
|
70e9e1ed3a | ||
|
efafdbebaa | ||
|
19967ce37c | ||
|
ce3d6fba37 | ||
|
3e14716fc6 | ||
|
43620cd9b6 | ||
|
e819140f36 | ||
|
f28f0eac1a | ||
|
ff4abb8dfe | ||
|
e2efaddfed | ||
|
b1db6c6fb1 | ||
|
279fc469ab | ||
|
d185fb6dd7 | ||
|
3a667a3809 | ||
|
a895775f81 | ||
|
0a9beddef9 | ||
|
29528e40b0 | ||
|
aaf0b702a3 | ||
|
9f376db0f4 | ||
|
391ce61362 | ||
|
62e2ca4c16 | ||
|
ea5af73901 | ||
|
7d7feda319 | ||
|
1c810f68f8 | ||
|
8528a80d7e | ||
|
dd0bf1a012 | ||
|
e0c4752bbf | ||
|
c896440525 | ||
|
1f042a8434 | ||
|
fc3383946d | ||
|
4abbebf5e9 | ||
|
eb0ad7f22e | ||
|
0b1c90718d | ||
|
47597b2b7c | ||
|
f3c55ba5f2 | ||
|
5e453e3227 | ||
|
9bf7f45354 | ||
|
c8bc511e04 | ||
|
85a114e591 | ||
|
73b7144394 | ||
|
e9f6a0a1d2 | ||
|
dfb32d4ebe | ||
|
682b0c1729 | ||
|
e79abb69eb | ||
|
514ed02693 | ||
|
ff3241bd57 | ||
|
76937bedc9 | ||
|
1e65da9aa4 | ||
|
0d49377879 | ||
|
1a490a8e7a | ||
|
e53265472f | ||
|
66fdbef90b | ||
|
80482e70a8 | ||
|
f214c3166b | ||
|
4a4303afef | ||
|
cc7bdc5b76 | ||
|
3539433a9d | ||
|
54cb821ae9 | ||
|
4924dcfd12 | ||
|
d84e76d07c | ||
|
eca215d044 | ||
|
721de3fba6 | ||
|
e7fa98008d | ||
|
923fbc54b8 | ||
|
ff39f90abd | ||
|
db30fa3c5e |
16
.github/workflows/build.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
jobs:
|
||||
build_macos:
|
||||
name: Build for MacOS
|
||||
runs-on: macos-10.15
|
||||
runs-on: macos-13
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v2
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16'
|
||||
go-version: '^1.17'
|
||||
- name: Cache Go Modules
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
build_windows:
|
||||
name: Build for Windows
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v2
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16'
|
||||
go-version: '^1.17'
|
||||
- name: Cache Go Modules
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
|
||||
build_linux:
|
||||
name: Build for Linux
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v2
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16'
|
||||
go-version: '^1.17'
|
||||
- name: Cache Go Modules
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./yarr-windows.zip
|
||||
asset_name: yarr-${{ github.ref }}-windows32.zip
|
||||
asset_name: yarr-${{ github.ref }}-windows64.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Upload Linux
|
||||
uses: actions/upload-release-asset@v1
|
||||
@@ -140,5 +140,5 @@ jobs:
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./yarr-linux.zip
|
||||
asset_name: yarr-${{ github.ref }}-linux32.zip
|
||||
asset_name: yarr-${{ github.ref }}-linux64.zip
|
||||
asset_content_type: application/zip
|
||||
|
2
.gitignore
vendored
@@ -1,5 +1,3 @@
|
||||
/server/assets.go
|
||||
/gofeed
|
||||
/_output
|
||||
/yarr
|
||||
*.db
|
||||
|
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "src/gofeed"]
|
||||
path = src/gofeed
|
||||
url = http://github.com/mmcdole/gofeed
|
45
cmd/feed2json/main.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/nkanaev/yarr/src/parser"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Println("usage: <script> [url|filepath]")
|
||||
return
|
||||
}
|
||||
url := os.Args[1]
|
||||
var r io.Reader
|
||||
|
||||
if strings.HasPrefix(url, "http") {
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get url %s: %s", url, err)
|
||||
}
|
||||
r = res.Body
|
||||
} else {
|
||||
var err error
|
||||
r, err = os.Open(url)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open file: %s", err)
|
||||
}
|
||||
}
|
||||
feed, err := parser.Parse(r)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to parse feed: %s", err)
|
||||
}
|
||||
body, err := json.MarshalIndent(feed, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to marshall feed: %s", err)
|
||||
}
|
||||
fmt.Println(string(body))
|
||||
}
|
@@ -1,12 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var rsrc = `1 VERSIONINFO
|
||||
var rsrc = `1 VERSIONINFO
|
||||
FILEVERSION {VERSION_COMMA},0,0
|
||||
PRODUCTVERSION {VERSION_COMMA},0,0
|
||||
BEGIN
|
@@ -85,9 +85,9 @@ func main() {
|
||||
for _, res := range []int{1024, 512, 256, 128, 64, 32, 16} {
|
||||
outfile := fmt.Sprintf("icon_%dx%d.png", res, res)
|
||||
if res == 1024 || res == 64 {
|
||||
outfile = fmt.Sprintf("icon_%dx%d@2x.png", res / 2, res / 2)
|
||||
outfile = fmt.Sprintf("icon_%dx%d@2x.png", res/2, res/2)
|
||||
}
|
||||
cmd := []string {
|
||||
cmd := []string{
|
||||
"sips", "-s", "format", "png", "--resampleWidth", strconv.Itoa(res),
|
||||
iconFile, "--out", path.Join(iconsetDir, outfile),
|
||||
}
|
41
cmd/readability/main.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/nkanaev/yarr/src/content/readability"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Println("usage: <script> [url]")
|
||||
return
|
||||
}
|
||||
url := os.Args[1]
|
||||
var r io.Reader
|
||||
|
||||
if strings.HasPrefix(url, "http") {
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get url %s: %s", url, err)
|
||||
}
|
||||
r = res.Body
|
||||
} else {
|
||||
var err error
|
||||
r, err = os.Open(url)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
content, err := readability.ExtractContent(r)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to extract content: %s", err)
|
||||
}
|
||||
fmt.Println(content)
|
||||
}
|
155
cmd/yarr/main.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/nkanaev/yarr/src/platform"
|
||||
"github.com/nkanaev/yarr/src/server"
|
||||
"github.com/nkanaev/yarr/src/storage"
|
||||
)
|
||||
|
||||
var Version string = "0.0"
|
||||
var GitHash string = "unknown"
|
||||
|
||||
var OptList = make([]string, 0)
|
||||
|
||||
func opt(envVar, defaultValue string) string {
|
||||
OptList = append(OptList, envVar)
|
||||
value := os.Getenv(envVar)
|
||||
if value != "" {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func parseAuthfile(authfile io.Reader) (username, password string, err error) {
|
||||
scanner := bufio.NewScanner(authfile)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
return "", "", fmt.Errorf("wrong syntax (expected `username:password`)")
|
||||
}
|
||||
username = parts[0]
|
||||
password = parts[1]
|
||||
break
|
||||
}
|
||||
return username, password, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
platform.FixConsoleIfNeeded()
|
||||
|
||||
var addr, db, authfile, auth, certfile, keyfile, basepath, logfile string
|
||||
var ver, open bool
|
||||
|
||||
flag.CommandLine.SetOutput(os.Stdout)
|
||||
|
||||
flag.Usage = func() {
|
||||
out := flag.CommandLine.Output()
|
||||
fmt.Fprintf(out, "Usage of %s:\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprintln(out, "\nThe environmental variables, if present, will be used to provide\nthe default values for the params above:")
|
||||
fmt.Fprintln(out, " ", strings.Join(OptList, ", "))
|
||||
}
|
||||
|
||||
flag.StringVar(&addr, "addr", opt("YARR_ADDR", "127.0.0.1:7070"), "address to run server on")
|
||||
flag.StringVar(&basepath, "base", opt("YARR_BASE", ""), "base path of the service url")
|
||||
flag.StringVar(&authfile, "auth-file", opt("YARR_AUTHFILE", ""), "`path` to a file containing username:password. Takes precedence over --auth (or YARR_AUTH)")
|
||||
flag.StringVar(&auth, "auth", opt("YARR_AUTH", ""), "string with username and password in the format `username:password`")
|
||||
flag.StringVar(&certfile, "cert-file", opt("YARR_CERTFILE", ""), "`path` to cert file for https")
|
||||
flag.StringVar(&keyfile, "key-file", opt("YARR_KEYFILE", ""), "`path` to key file for https")
|
||||
flag.StringVar(&db, "db", opt("YARR_DB", ""), "storage file `path`")
|
||||
flag.StringVar(&logfile, "log-file", opt("YARR_LOGFILE", ""), "`path` to log file to use instead of stdout")
|
||||
flag.BoolVar(&ver, "version", false, "print application version")
|
||||
flag.BoolVar(&open, "open", false, "open the server in browser")
|
||||
flag.Parse()
|
||||
|
||||
if ver {
|
||||
fmt.Printf("v%s (%s)\n", Version, GitHash)
|
||||
return
|
||||
}
|
||||
|
||||
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
|
||||
if logfile != "" {
|
||||
file, err := os.OpenFile(logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to setup log file: ", err)
|
||||
}
|
||||
defer file.Close()
|
||||
log.SetOutput(file)
|
||||
} else {
|
||||
log.SetOutput(os.Stdout)
|
||||
}
|
||||
|
||||
configPath, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to get config dir: ", err)
|
||||
}
|
||||
|
||||
if db == "" {
|
||||
storagePath := filepath.Join(configPath, "yarr")
|
||||
if err := os.MkdirAll(storagePath, 0755); err != nil {
|
||||
log.Fatal("Failed to create app config dir: ", err)
|
||||
}
|
||||
db = filepath.Join(storagePath, "storage.db")
|
||||
}
|
||||
|
||||
log.Printf("using db file %s", db)
|
||||
|
||||
var username, password string
|
||||
if authfile != "" {
|
||||
f, err := os.Open(authfile)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to open auth file: ", err)
|
||||
}
|
||||
defer f.Close()
|
||||
username, password, err = parseAuthfile(f)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to parse auth file: ", err)
|
||||
}
|
||||
} else if auth != "" {
|
||||
username, password, err = parseAuthfile(strings.NewReader(auth))
|
||||
if err != nil {
|
||||
log.Fatal("Failed to parse auth literal: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
if (certfile != "" || keyfile != "") && (certfile == "" || keyfile == "") {
|
||||
log.Fatalf("Both cert & key files are required")
|
||||
}
|
||||
|
||||
store, err := storage.New(db)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to initialise database: ", err)
|
||||
}
|
||||
|
||||
srv := server.NewServer(store, addr)
|
||||
|
||||
if basepath != "" {
|
||||
srv.BasePath = "/" + strings.Trim(basepath, "/")
|
||||
}
|
||||
|
||||
if certfile != "" && keyfile != "" {
|
||||
srv.CertFile = certfile
|
||||
srv.KeyFile = keyfile
|
||||
}
|
||||
|
||||
if username != "" && password != "" {
|
||||
srv.Username = username
|
||||
srv.Password = password
|
||||
}
|
||||
|
||||
log.Printf("starting server at %s", srv.GetAddr())
|
||||
if open {
|
||||
platform.Open(srv.GetAddr())
|
||||
}
|
||||
platform.Start(srv)
|
||||
}
|
47
cmd/yarr/main_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPasswordFromAuthfile(t *testing.T) {
|
||||
for _, tc := range [...]struct {
|
||||
authfile string
|
||||
expectedUsername string
|
||||
expectedPassword string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
authfile: "username:password",
|
||||
expectedUsername: "username",
|
||||
expectedPassword: "password",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
authfile: "username-and-no-password",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
authfile: "username:password:with:columns",
|
||||
expectedUsername: "username",
|
||||
expectedPassword: "password:with:columns",
|
||||
expectedError: false,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.authfile, func(t *testing.T) {
|
||||
username, password, err := parseAuthfile(strings.NewReader(tc.authfile))
|
||||
if tc.expectedUsername != username {
|
||||
t.Errorf("expected username %q, got %q", tc.expectedUsername, username)
|
||||
}
|
||||
if tc.expectedPassword != password {
|
||||
t.Errorf("expected password %q, got %q", tc.expectedPassword, password)
|
||||
}
|
||||
if tc.expectedError && err == nil {
|
||||
t.Errorf("expected error, got nil")
|
||||
} else if !tc.expectedError && err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
44
doc/build.md
Normal file
@@ -0,0 +1,44 @@
|
||||
## Compilation
|
||||
|
||||
Install `Go >= 1.17` and `GCC`. Get the source code:
|
||||
|
||||
git clone https://github.com/nkanaev/yarr.git
|
||||
|
||||
Then run one of the corresponding commands:
|
||||
|
||||
# create an executable for the host os
|
||||
make build_macos # -> _output/macos/yarr.app
|
||||
make build_linux # -> _output/linux/yarr
|
||||
make build_windows # -> _output/windows/yarr.exe
|
||||
|
||||
# host-specific cli version (no gui)
|
||||
make build_default # -> _output/yarr
|
||||
|
||||
# ... or start a dev server locally
|
||||
make serve # starts a server at http://localhost:7070
|
||||
|
||||
# ... or build a docker image
|
||||
docker build -t yarr -f etc/dockerfile .
|
||||
|
||||
## ARM compilation
|
||||
|
||||
The instructions below are to cross-compile *yarr* to `Linux/ARM*`.
|
||||
|
||||
Build:
|
||||
|
||||
docker build -t yarr.arm -f etc/dockerfile.arm .
|
||||
|
||||
Test:
|
||||
|
||||
# inside host
|
||||
docker run -it --rm yarr.arm
|
||||
|
||||
# then, inside container
|
||||
cd /root/out
|
||||
qemu-aarch64 -L /usr/aarch64-linux-gnu/ yarr.arm64
|
||||
|
||||
Extract files from images:
|
||||
|
||||
CID=$(docker create yarr.arm)
|
||||
docker cp -a "$CID:/root/out" .
|
||||
docker rm "$CID"
|
@@ -1,35 +0,0 @@
|
||||
# v1.4 (2021-03-11)
|
||||
|
||||
- (new) keyboard shortcuts (thanks to @Duarte-Dias)
|
||||
- (new) show podcast audio
|
||||
- (fix) deleting feeds
|
||||
- (etc) minor ui tweaks & changes
|
||||
|
||||
# v1.3 (2021-02-18)
|
||||
|
||||
- (fix) log out functionality if authentication is set
|
||||
- (fix) import opml if authentication is set
|
||||
- (fix) login page if authentication is set (thanks to @einschmidt)
|
||||
|
||||
# v1.2 (2021-02-11)
|
||||
|
||||
- (new) autorefresh rate
|
||||
- (new) reduced bandwidth usage via stateful http headers `last-modified/etag`
|
||||
- (new) show feed errors in feed management modal
|
||||
- (new) `-open` flag for automatically opening the server url
|
||||
- (new) `-base` flag for serving urls under non-root path (thanks to @hcl)
|
||||
- (new) `-auth-file` flag for authentication
|
||||
- (new) `-cert-file` & `-key-file` flags for TLS
|
||||
- (fix) wrapping long words in the ui to prevent vertical scroll
|
||||
- (fix) increased toolbar height in mobile/tablet layout (thanks to @einschmidt)
|
||||
|
||||
# v1.1 (2020-10-05)
|
||||
|
||||
- (new) responsive design
|
||||
- (fix) server crash on favicon fetch timeout (reported by @minioin)
|
||||
- (fix) handling byte order marks in feeds (reported by @ilaer)
|
||||
- (fix) deleting a feed raises exception in the ui if the feed's items are shown.
|
||||
|
||||
# v1.0 (2020-09-24)
|
||||
|
||||
Initial Release
|
101
doc/changelog.txt
Normal file
@@ -0,0 +1,101 @@
|
||||
# upcoming
|
||||
|
||||
- (new) Fever API support (thanks to @icefed)
|
||||
- (fix) duplicate articles caused by the same feed addition (thanks to @adaszko)
|
||||
- (fix) relative article links (thanks to @adazsko for the report)
|
||||
- (fix) atom article links stored in id element (thanks to @adazsko for the report)
|
||||
- (fix) parsing atom feed titles (thanks to @wnh)
|
||||
|
||||
# v2.4 (2023-08-15)
|
||||
|
||||
- (new) ARM build support (thanks to @tillcash & @fenuks)
|
||||
- (new) auth configuration via param or env variable (thanks to @pierreprinetti)
|
||||
- (new) web app manifest for an app-like experience on mobile (thanks to @qbit)
|
||||
- (fix) concurrency issue crashing the app (thanks to @quoing)
|
||||
- (fix) favicon visibility in dark mode (thanks to @caycaycarly for the report)
|
||||
- (fix) autoloading more articles not working in certain edge cases (thanks to @fenuks for the report)
|
||||
- (fix) handle Google URL redirects in "Read Here" (thanks to @cubbei for discovery)
|
||||
- (fix) handle failures to extract content in "Read Here" (thanks to @grigio for the report)
|
||||
- (fix) article view width for high resolution screens (thanks to @whaler-ragweed for the report)
|
||||
- (fix) make newly added feed searchable (thanks to @BMorearty for the report)
|
||||
- (fix) feed/article selection accessibility via arrow keys (thanks to @grigio and @tillcash)
|
||||
- (fix) keyboard shortcuts in Firefox (thanks to @kaloyan13)
|
||||
- (fix) keyboard shortcuts in non-English layouts (thanks to @kaloyan13)
|
||||
- (fix) sorting articles with timezone information (thanks to @x2cf)
|
||||
- (fix) handling links set in guid only for certain feeds (thanks to @adaszko for the report)
|
||||
- (fix) crashes caused by feed icon endpoint (thanks to @adaszko)
|
||||
|
||||
# v2.3 (2022-05-03)
|
||||
|
||||
- (fix) handling encodings (thanks to @f100024 & @fserb)
|
||||
- (fix) parsing xml feeds with illegal characters (thanks to @stepelu for the report)
|
||||
- (fix) old articles reappearing as unread (thanks to @adaszko for the report)
|
||||
- (fix) item list scrolling issue on large screens (thanks to @bielej for the report)
|
||||
- (fix) keyboard shortcuts color in dark mode (thanks to @John09f9 for the report)
|
||||
- (etc) autofocus when adding a new feed (thanks to @lakuapik)
|
||||
|
||||
# v2.2 (2021-11-20)
|
||||
|
||||
- (fix) windows console support (thanks to @dufferzafar for the report)
|
||||
- (fix) remove html tags from article titles (thanks to Alex Went for the report)
|
||||
- (etc) autoselect current folder when adding a new feed (thanks to @krkk)
|
||||
- (etc) folder/feed settings menu available across all filters
|
||||
|
||||
# v2.1 (2021-08-16)
|
||||
|
||||
- (new) configuration via env variables
|
||||
- (fix) missing `content-type` headers (thanks to @verahawk for the report)
|
||||
- (fix) handle opml files not following the spec (thanks to @huangnauh for the report)
|
||||
- (fix) pagination in unread/starred feeds (thanks to @Farow for the report)
|
||||
- (fix) handling feeds with non-utf8 encodings (thanks to @fserb for the report)
|
||||
- (fix) errors caused by empty feeds (thanks to @decke)
|
||||
- (fix) recognize all audio mime types as podcasts (thanks to @krkk)
|
||||
- (fix) ui tweaks (thanks to @Farow)
|
||||
|
||||
# v2.0 (2021-04-18)
|
||||
|
||||
- (new) user interface tweaks
|
||||
- (new) feed parser fully rewritten
|
||||
- (new) show youtube/vimeo iframes in "read here"
|
||||
- (new) keyboard shortcuts for article scrolling & toggling "read here"
|
||||
- (new) more options for auto-refresh intervals
|
||||
- (fix) `-base` not serving static files (thanks to @vfaronov)
|
||||
- (etc) 3rd-party dependencies reduced to the bare minimum
|
||||
|
||||
special thanks to @tillcash for feedback & suggestions.
|
||||
|
||||
# v1.4 (2021-03-11)
|
||||
|
||||
- (new) keyboard shortcuts (thanks to @Duarte-Dias)
|
||||
- (new) show podcast audio
|
||||
- (fix) deleting feeds
|
||||
- (etc) minor ui tweaks & changes
|
||||
|
||||
# v1.3 (2021-02-18)
|
||||
|
||||
- (fix) log out functionality if authentication is set
|
||||
- (fix) import opml if authentication is set
|
||||
- (fix) login page if authentication is set (thanks to @einschmidt)
|
||||
|
||||
# v1.2 (2021-02-11)
|
||||
|
||||
- (new) autorefresh rate
|
||||
- (new) reduced bandwidth usage via stateful http headers `last-modified/etag`
|
||||
- (new) show feed errors in feed management modal
|
||||
- (new) `-open` flag for automatically opening the server url
|
||||
- (new) `-base` flag for serving urls under non-root path (thanks to @hcl)
|
||||
- (new) `-auth-file` flag for authentication
|
||||
- (new) `-cert-file` & `-key-file` flags for TLS
|
||||
- (fix) wrapping long words in the ui to prevent vertical scroll
|
||||
- (fix) increased toolbar height in mobile/tablet layout (thanks to @einschmidt)
|
||||
|
||||
# v1.1 (2020-10-05)
|
||||
|
||||
- (new) responsive design
|
||||
- (fix) server crash on favicon fetch timeout (reported by @minioin)
|
||||
- (fix) handling byte order marks in feeds (reported by @ilaer)
|
||||
- (fix) deleting a feed raises exception in the ui if the feed's items are shown.
|
||||
|
||||
# v1.0 (2020-09-24)
|
||||
|
||||
Initial Release
|
19
doc/fever.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Fever API support
|
||||
|
||||
Fever API is a kind of RSS HTTP API interface, because the Fever API definition is not very clear, so the implementation of Fever server and Client may have some compatibility problems.
|
||||
|
||||
The Fever API implemented by Yarr is based on the Fever API spec: https://github.com/DigitalDJ/tinytinyrss-fever-plugin/blob/master/fever-api.md.
|
||||
|
||||
Here are some Apps that have been tested to work with yarr. Feel free to test other Clients/Apps and update the list here.
|
||||
|
||||
> Different apps support different URL/Address formats. Please note whether the URL entered has `http://` scheme and `/` suffix.
|
||||
|
||||
| App | Platforms | Config Server URL |
|
||||
|:------------------------------------------------------------------------- | ---------------- |:--------------------------------------------------- |
|
||||
| [Reeder](https://reederapp.com/) | MacOS<br>iOS | 127.0.0.1:7070/fever<br>http://127.0.0.1:7070/fever |
|
||||
| [ReadKit](https://readkit.app/) | MacOS<br>iOS | http://127.0.0.1:7070/fever |
|
||||
| [Fluent Reader](https://github.com/yang991178/fluent-reader) | MacOS<br>Windows | http://127.0.0.1:7070/fever/ |
|
||||
| [Unread](https://apps.apple.com/us/app/unread-an-rss-reader/id1363637349) | iOS | http://127.0.0.1:7070/fever |
|
||||
| [Fiery Feeds](https://voidstern.net/fiery-feeds) | MacOS<br>iOS | http://127.0.0.1:7070/fever |
|
||||
|
||||
If you are having trouble using Fever, please open an issue and @icefed, thanks.
|
171
doc/formats.txt
Normal file
@@ -0,0 +1,171 @@
|
||||
# model
|
||||
|
||||
- feed:
|
||||
- title
|
||||
|
||||
rdf>channel>title (rss 0.90)
|
||||
rdf>channel>title (rss 1.0)
|
||||
rss>channel>title (rss 0.91 netscape)
|
||||
rss>channel>title (rss 0.91 userland)
|
||||
rss>channel>title (rss 2.0)
|
||||
feed>title (atom 1.0)
|
||||
|
||||
- site_url
|
||||
|
||||
rdf>channel>link (rss 0.90)
|
||||
rdf>channel>link (rss 1.0)
|
||||
rss>channel>link (rss 0.91 netscape)
|
||||
rss>channel>link (rss 0.91 userland)
|
||||
rss>channel>link (rss 2.0)
|
||||
feed>link (atom 1.0)
|
||||
|
||||
- item:
|
||||
- guid
|
||||
|
||||
rss>channel>guid (rss 2.0)
|
||||
feed>entry>id (atom 1.0)
|
||||
|
||||
- date
|
||||
|
||||
rdf>item>dc:date (rss 1.0)
|
||||
rss>channel>pubDate (rss 2.0)
|
||||
feed>entry>updated (atom 1.0)
|
||||
feed>entry>published (atom 1.0)
|
||||
|
||||
- url
|
||||
|
||||
rdf>item>link (rss 0.90)
|
||||
rdf>item>link (rss 1.0)
|
||||
rss>channel>item>link (rss 0.91 netscape)
|
||||
rss>channel>item>link (rss 0.91 userland)
|
||||
rss>channel>item>link (rss 2.0)
|
||||
feed>entry>link[rel=alternate] (atom 1.0)
|
||||
|
||||
- title
|
||||
|
||||
rdf>item>title (rss 0.90)
|
||||
rdf>item>title (rss 1.0)
|
||||
rss>channel>item>title (rss 0.91 netscape)
|
||||
rss>channel>item>title (rss 0.91 userland)
|
||||
rss>channel>item>title (rss 2.0)
|
||||
feed>entry>title (atom 1.0)
|
||||
|
||||
- content
|
||||
|
||||
rss>channel>item>description (rss 0.91 netscape)
|
||||
rss>channel>item>description (rss 0.91 userland)
|
||||
rss>channel>item>description (rss 2.0)
|
||||
rdf>item>description (rss 1.0)
|
||||
rdf>item>content:encoded (rss 1.0)
|
||||
feed>entry>content (atom 1.0)
|
||||
|
||||
- image_url
|
||||
|
||||
rss>item>media:thumbnail:url (rss 2.0 media)
|
||||
feed>entry>enclosure[rel='image/*'] (atom 1.0) ???
|
||||
|
||||
- audio_url
|
||||
|
||||
rss>item>enclosure:url (audio/*) (rss 2.0)
|
||||
feed>entry>enclosure (audio/*') (atom 1.0) ???
|
||||
|
||||
# specs
|
||||
|
||||
- rss
|
||||
https://en.wikipedia.org/wiki/RSS
|
||||
- 0.90:
|
||||
https://www.rssboard.org/rss-0-9-0
|
||||
https://web.archive.org/web/20001208063100/http://my.netscape.com/publish/help/quickstart.html
|
||||
- 0.91 (netscape)
|
||||
https://www.rssboard.org/rss-0-9-1-netscape
|
||||
- 0.91 (userland)
|
||||
https://www.rssboard.org/rss-0-9-1
|
||||
- 0.92
|
||||
https://www.rssboard.org/rss-0-9-2
|
||||
by userland, no significant changes from 0.91
|
||||
- 0.93 (withdrawn)
|
||||
http://backend.userland.com/rss093
|
||||
- 0.94 (withdrawn)
|
||||
- 1.0
|
||||
https://web.resource.org/rss/1.0/
|
||||
https://web.archive.org/web/20021014094554/https://web.resource.org/rss/1.0/spec
|
||||
reintroduced rdf from 0.90, added dublincore namespaces etc
|
||||
namespaces:
|
||||
content: http://purl.org/rss/1.0/modules/content/
|
||||
dc: http://purl.org/dc/elements/1.1/
|
||||
- 2.0
|
||||
https://cyber.harvard.edu/rss/rss.html
|
||||
https://www.rssboard.org/rss-2-0
|
||||
|
||||
- atom
|
||||
https://en.wikipedia.org/wiki/Atom_(Web_standard)
|
||||
- 0.3
|
||||
https://support.google.com/merchants/answer/160598?hl=en
|
||||
http://web.archive.org/web/20060811235523/http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html
|
||||
- 1.0
|
||||
https://tools.ietf.org/html/rfc4287
|
||||
https://validator.w3.org/feed/docs/atom.html
|
||||
|
||||
- json
|
||||
https://en.wikipedia.org/wiki/JSON_Feed
|
||||
- 1.0
|
||||
https://jsonfeed.org/version/1
|
||||
- 1.1
|
||||
https://jsonfeed.org/version/1.1
|
||||
|
||||
- media
|
||||
https://www.rssboard.org/media-rss
|
||||
xml namespace for:
|
||||
- rss 2.0
|
||||
- atom 1.0
|
||||
|
||||
# extensions
|
||||
|
||||
- feedburner
|
||||
https://en.wikipedia.org/wiki/FeedBurner
|
||||
|
||||
- media
|
||||
https://www.rssboard.org/media-rss
|
||||
initially for rss 2.0, used in atom 1.0 as well (youtube)
|
||||
|
||||
- itunes podcasts
|
||||
https://help.apple.com/itc/podcasts_connect/#/itcb54353390
|
||||
https://github.com/simplepie/simplepie-ng/wiki/Spec:-iTunes-Podcast-RSS
|
||||
|
||||
- google podcasts
|
||||
https://support.google.com/podcast-publishers/answer/9889544?visit_id=637523492443301715-1225759684&rd=1
|
||||
|
||||
# parsers
|
||||
|
||||
https://github.com/kurtmckee/feedparser
|
||||
https://github.com/mmcdole/gofeed
|
||||
https://github.com/miniflux/v2/tree/2.0.28/reader/
|
||||
https://github.com/Ranchero-Software/RSParser
|
||||
https://github.com/feederco/feeder-parser
|
||||
|
||||
https://github.com/mmcdole/gofeed/commit/9665eb31016cef3d15ab85574bc6fdbe890cd252
|
||||
|
||||
# platforms
|
||||
|
||||
A list of centralized content providers worth keeping track of.
|
||||
The parser should be reasonably handle content provided by them.
|
||||
Delete any from the list in case they drop support of web feeds.
|
||||
|
||||
- blogger
|
||||
- cnblogs
|
||||
- flickr
|
||||
- hatenablog
|
||||
- livejournal
|
||||
- medium
|
||||
- posthaven
|
||||
- reddit
|
||||
- substack
|
||||
- tumblr
|
||||
- vimeo
|
||||
- wordpress
|
||||
- youtube
|
||||
|
||||
# links
|
||||
|
||||
https://indieweb.org/feed#Criticism
|
||||
https://inessential.com/2013/03/18/brians_stupid_feed_tricks
|
27
doc/thirdparty.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
Below is the list of 3-rd party code directly included & rewritten
|
||||
to suit the author's needs & preferences.
|
||||
The licenses are included, and the authorship comments are left intact.
|
||||
|
||||
- readability
|
||||
https://github.com/miniflux/v2 (commit:31435ef) Apache 2.0
|
||||
|
||||
removed goquery dependency
|
||||
removed assisting utility structs (need another way to debug node scores)
|
||||
|
||||
- sanitizer
|
||||
https://github.com/miniflux/v2 (commit:3cb04b2) Apache 2.0
|
||||
|
||||
whitelist changed to the ones from https://github.com/cure53/DOMPurify:
|
||||
- allowed tags
|
||||
- allowed uri schemes
|
||||
- added svg whitelist
|
||||
|
||||
- systray
|
||||
https://github.com/getlantern/systray (commit:2c0986d) Apache 2.0
|
||||
|
||||
removed golog dependency
|
||||
|
||||
- fixconsole
|
||||
https://github.com/apenwarr/fixconsole (commit:5a9f648) Apache 2.0
|
||||
|
||||
removed `w32` dependency
|
@@ -1,4 +0,0 @@
|
||||
- fix: loading items (by scrolling down) is glitching while feeds are refreshing
|
||||
- ref: switch to the standard logger
|
||||
- ref: drop goquery, switch to cascadia
|
||||
- ref: organize "server" package using KonMari method
|
||||
|
44
etc/dockerfile.arm
Normal file
@@ -0,0 +1,44 @@
|
||||
FROM ubuntu:20.04
|
||||
|
||||
# Install GCC
|
||||
RUN apt update
|
||||
RUN apt install -y \
|
||||
wget build-essential \
|
||||
gcc-aarch64-linux-gnu \
|
||||
binutils-aarch64-linux-gnu binutils-aarch64-linux-gnu-dbg \
|
||||
gcc-arm-linux-gnueabihf \
|
||||
binutils-arm-linux-gnueabihf binutils-arm-linux-gnueabihf-dbg
|
||||
RUN env DEBIAN_FRONTEND=noninteractive \
|
||||
apt install -y qemu-user qemu-user-static
|
||||
|
||||
# Install Golang
|
||||
RUN wget --quiet https://go.dev/dl/go1.18.2.linux-amd64.tar.gz && \
|
||||
rm -rf /usr/local/go && \
|
||||
tar -C /usr/local -xzf go1.18.2.linux-amd64.tar.gz
|
||||
ENV PATH=$PATH:/usr/local/go/bin
|
||||
|
||||
# Copy source code
|
||||
WORKDIR /root/src
|
||||
RUN mkdir /root/out
|
||||
COPY . .
|
||||
|
||||
# Build ARM64
|
||||
RUN env \
|
||||
CC=aarch64-linux-gnu-gcc \
|
||||
CGO_ENABLED=1 \
|
||||
GOOS=linux GOARCH=arm64 \
|
||||
go build \
|
||||
-tags "sqlite_foreign_keys linux" \
|
||||
-ldflags="-s -w" \
|
||||
-o /root/out/yarr.arm64 ./cmd/yarr
|
||||
|
||||
RUN env \
|
||||
CC=arm-linux-gnueabihf-gcc \
|
||||
CGO_ENABLED=1 \
|
||||
GOOS=linux GOARCH=arm GOARM=7 \
|
||||
go build \
|
||||
-tags "sqlite_foreign_keys linux" \
|
||||
-ldflags="-s -w" \
|
||||
-o /root/out/yarr.arm7 ./cmd/yarr
|
||||
|
||||
CMD ["/bin/bash"]
|
23
etc/install-linux.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
cat >"$HOME/.local/share/applications/yarr.desktop" <<END
|
||||
[Desktop Entry]
|
||||
Name=yarr
|
||||
Exec=$HOME/.local/bin/yarr -open
|
||||
Icon=yarr
|
||||
Type=Application
|
||||
Categories=Internet;
|
||||
END
|
||||
|
||||
cat >"$HOME/.local/share/icons/yarr.svg" <<END
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-anchor-favicon">
|
||||
<circle cx="12" cy="5" r="3" stroke-width="4" stroke="#ffffff"></circle>
|
||||
<line x1="12" y1="22" x2="12" y2="8" stroke-width="4" stroke="#ffffff"></line>
|
||||
<path d="M5 12H2a10 10 0 0 0 20 0h-3" stroke-width="4" stroke="#ffffff"></path>
|
||||
|
||||
<circle cx="12" cy="5" r="3"></circle>
|
||||
<line x1="12" y1="22" x2="12" y2="8"></line>
|
||||
<path d="M5 12H2a10 10 0 0 0 20 0h-3"></path>
|
||||
</svg>
|
||||
END
|
BIN
etc/promo.png
Before Width: | Height: | Size: 727 KiB After Width: | Height: | Size: 173 KiB |
12
go.mod
@@ -1,13 +1,11 @@
|
||||
module github.com/nkanaev/yarr
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.5.1
|
||||
github.com/getlantern/systray v1.0.4
|
||||
github.com/mattn/go-sqlite3 v1.14.0
|
||||
github.com/mmcdole/gofeed v1.0.0
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
|
||||
github.com/mattn/go-sqlite3 v1.14.7
|
||||
golang.org/x/net v0.8.0
|
||||
golang.org/x/sys v0.6.0
|
||||
)
|
||||
|
||||
replace github.com/mmcdole/gofeed => ./src/gofeed
|
||||
require golang.org/x/text v0.8.0 // indirect
|
||||
|
93
go.sum
@@ -1,62 +1,39 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
|
||||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So=
|
||||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
|
||||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk=
|
||||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc=
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||
github.com/getlantern/systray v1.0.4 h1:qJ/bOlYhn5nsj2FejutWWVFMbhOkYhsChoy26OjgZgU=
|
||||
github.com/getlantern/systray v1.0.4/go.mod h1:AecygODWIsBquJCJFop8MEQcJbWFfw/1yWbVabNgpCM=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf h1:sWGE2v+hO0Nd4yFU/S/mDBM5plIU8v/Qhfz41hkDIAI=
|
||||
github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf/go.mod h1:pasqhqstspkosTneA62Nc+2p9SOBBYAPbnmRRWPQ0V8=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/urfave/cli v1.22.3/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
|
||||
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
25
makefile
@@ -1,4 +1,4 @@
|
||||
VERSION=1.4
|
||||
VERSION=2.4
|
||||
GITHASH=$(shell git rev-parse --short=8 HEAD)
|
||||
|
||||
CGO_ENABLED=1
|
||||
@@ -8,29 +8,26 @@ GO_LDFLAGS := $(GO_LDFLAGS) -X 'main.Version=$(VERSION)' -X 'main.GitHash=$(GITH
|
||||
|
||||
build_default:
|
||||
mkdir -p _output
|
||||
go build -tags "sqlite_foreign_keys release" -ldflags="$(GO_LDFLAGS)" -o _output/yarr src/main.go
|
||||
go build -tags "sqlite_foreign_keys" -ldflags="$(GO_LDFLAGS)" -o _output/yarr ./cmd/yarr
|
||||
|
||||
build_macos:
|
||||
set GOOS=darwin
|
||||
set GOARCH=amd64
|
||||
mkdir -p _output/macos
|
||||
go build -tags "sqlite_foreign_keys release macos" -ldflags="$(GO_LDFLAGS)" -o _output/macos/yarr src/main.go
|
||||
GOOS=darwin GOARCH=amd64 go build -tags "sqlite_foreign_keys macos" -ldflags="$(GO_LDFLAGS)" -o _output/macos/yarr ./cmd/yarr
|
||||
cp src/platform/icon.png _output/macos/icon.png
|
||||
go run bin/package_macos.go -outdir _output/macos -version "$(VERSION)"
|
||||
go run ./cmd/package_macos -outdir _output/macos -version "$(VERSION)"
|
||||
|
||||
build_linux:
|
||||
set GOOS=linux
|
||||
set GOARCH=386
|
||||
mkdir -p _output/linux
|
||||
go build -tags "sqlite_foreign_keys release linux" -ldflags="$(GO_LDFLAGS)" -o _output/linux/yarr src/main.go
|
||||
GOOS=linux GOARCH=amd64 go build -tags "sqlite_foreign_keys linux" -ldflags="$(GO_LDFLAGS)" -o _output/linux/yarr ./cmd/yarr
|
||||
|
||||
build_windows:
|
||||
set GOOS=windows
|
||||
set GOARCH=386
|
||||
mkdir -p _output/windows
|
||||
go run bin/generate_versioninfo.go -version "$(VERSION)" -outfile src/platform/versioninfo.rc
|
||||
go run ./cmd/generate_versioninfo -version "$(VERSION)" -outfile src/platform/versioninfo.rc
|
||||
windres -i src/platform/versioninfo.rc -O coff -o src/platform/versioninfo.syso
|
||||
go build -tags "sqlite_foreign_keys release windows" -ldflags="$(GO_LDFLAGS) -H windowsgui" -o _output/windows/yarr.exe src/main.go
|
||||
GOOS=windows GOARCH=amd64 go build -tags "sqlite_foreign_keys windows" -ldflags="$(GO_LDFLAGS) -H windowsgui" -o _output/windows/yarr.exe ./cmd/yarr
|
||||
|
||||
serve:
|
||||
go run -tags "sqlite_foreign_keys" src/main.go -db local.db
|
||||
go run -tags "sqlite_foreign_keys" ./cmd/yarr -db local.db
|
||||
|
||||
test:
|
||||
cd src && go test -tags "sqlite_foreign_keys" ./...
|
||||
|
64
readme.md
@@ -3,72 +3,36 @@
|
||||
**yarr** (yet another rss reader) is a web-based feed aggregator which can be used both
|
||||
as a desktop application and a personal self-hosted server.
|
||||
|
||||
It is written in Go with the frontend in Vue.js. The storage is backed by SQLite.
|
||||
The app is a single binary with an embedded database (SQLite).
|
||||
|
||||

|
||||
|
||||
## usage
|
||||
|
||||
The latest prebuilt binaries for Linux/MacOS/Windows are available
|
||||
[here](https://github.com/nkanaev/yarr/releases/latest).
|
||||
The latest prebuilt binaries for Linux/MacOS/Windows AMD64 are available
|
||||
[here](https://github.com/nkanaev/yarr/releases/latest). Installation instructions:
|
||||
|
||||
### macos
|
||||
* MacOS
|
||||
|
||||
Download `yarr-*-macos64.zip`, unzip it, place `yarr.app` in `/Applications` folder.
|
||||
Download `yarr-*-macos64.zip`, unzip it, place `yarr.app` in `/Applications` folder, [open the app][macos-open], click the anchor menu bar icon, select "Open".
|
||||
|
||||
The binaries are not signed, because the author doesn't want to buy a certificate.
|
||||
Apple hates cheapskate developers, therefore the OS will refuse to run the application.
|
||||
To bypass these measures, you can run the command:
|
||||
* Windows
|
||||
|
||||
xattr -d com.apple.quarantine /Applications/yarr.app
|
||||
Download `yarr-*-windows64.zip`, unzip it, open `yarr.exe`, click the anchor system tray icon, select "Open".
|
||||
|
||||
### windows
|
||||
* Linux
|
||||
|
||||
Download `yarr-*-windows32.zip`, unzip it, place wherever you'd like to
|
||||
(`C:\Program Files` or Recycle Bin). Create a shortcut manually if you'd like to.
|
||||
Download `yarr-*-linux64.zip`, unzip it, place `yarr` in `$HOME/.local/bin`
|
||||
and run [the script](etc/install-linux.sh).
|
||||
|
||||
Microsoft doesn't like cheapskate developers too,
|
||||
but might only gently warn you about that, which you can safely ignore.
|
||||
|
||||
### linux
|
||||
|
||||
The Linux version doesn't come with the desktop environment integration.
|
||||
For easy access on DE it is recommended to create a desktop menu entry by
|
||||
by following the steps below:
|
||||
|
||||
unzip -x yarr*.zip
|
||||
sudo mv yarr /usr/local/bin/yarr
|
||||
sudo nano /usr/local/share/applications/yarr.desktop
|
||||
|
||||
and pasting the content:
|
||||
|
||||
[Desktop Entry]
|
||||
Name=yarr
|
||||
Exec=/usr/local/bin/yarr -open
|
||||
Icon=rss
|
||||
Type=Application
|
||||
Categories=Internet;
|
||||
[macos-open]: https://support.apple.com/en-gb/guide/mac-help/mh40616/mac
|
||||
|
||||
For self-hosting, see `yarr -h` for auth, tls & server configuration flags.
|
||||
|
||||
## build
|
||||
See more:
|
||||
|
||||
Install `Go >= 1.16` and `gcc`. Get the source code:
|
||||
|
||||
git clone --recurse-submodules https://github.com/nkanaev/yarr.git
|
||||
|
||||
Then run one of the corresponding commands:
|
||||
|
||||
# create an executable for the host os
|
||||
make build_macos # -> _output/macos/yarr.app
|
||||
make build_linux # -> _output/linux/yarr
|
||||
make build_windows # -> _output/windows/yarr.exe
|
||||
|
||||
# ... or start a dev server locally
|
||||
make serve # starts a server at http://localhost:7070
|
||||
|
||||
# ... or build a docker image
|
||||
docker build -t yarr .
|
||||
* [Building from source code](doc/build.md)
|
||||
* [Fever API support](doc/fever.md)
|
||||
|
||||
## credits
|
||||
|
||||
|
@@ -4,8 +4,9 @@ import (
|
||||
"embed"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
@@ -23,15 +24,24 @@ func (afs assetsfs) Open(name string) (fs.File, error) {
|
||||
return os.DirFS("src/assets").Open(name)
|
||||
}
|
||||
|
||||
func Render(path string, writer io.Writer, data interface{}) {
|
||||
func Template(path string) *template.Template {
|
||||
var tmpl *template.Template
|
||||
tmpl, found := FS.templates[path]
|
||||
if !found {
|
||||
tmpl = template.Must(template.New(path).Delims("{%", "%}").Funcs(template.FuncMap{
|
||||
"inline": func(svg string) template.HTML {
|
||||
svgfile, _ := FS.Open("graphicarts/" + svg)
|
||||
content, _ := ioutil.ReadAll(svgfile)
|
||||
svgfile.Close()
|
||||
svgfile, err := FS.Open("graphicarts/" + svg)
|
||||
// should never happen
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer svgfile.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(svgfile)
|
||||
// should never happen
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return template.HTML(content)
|
||||
},
|
||||
}).ParseFS(FS, path))
|
||||
@@ -39,6 +49,11 @@ func Render(path string, writer io.Writer, data interface{}) {
|
||||
FS.templates[path] = tmpl
|
||||
}
|
||||
}
|
||||
return tmpl
|
||||
}
|
||||
|
||||
func Render(path string, writer io.Writer, data interface{}) {
|
||||
tmpl := Template(path)
|
||||
tmpl.Execute(writer, data)
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,3 @@
|
||||
// +build release
|
||||
|
||||
package assets
|
||||
|
||||
import "embed"
|
||||
@@ -8,8 +6,9 @@ import "embed"
|
||||
//go:embed graphicarts
|
||||
//go:embed javascripts
|
||||
//go:embed stylesheets
|
||||
//go:embed manifest.json
|
||||
var embedded embed.FS
|
||||
|
||||
func init() {
|
||||
FS.embedded = &embedded
|
||||
FS.embedded = &embedded
|
||||
}
|
||||
|
Before Width: | Height: | Size: 395 B |
BIN
src/assets/graphicarts/android/android-launchericon-144-144.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
src/assets/graphicarts/android/android-launchericon-192-192.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
src/assets/graphicarts/android/android-launchericon-48-48.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/assets/graphicarts/android/android-launchericon-512-512.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
src/assets/graphicarts/android/android-launchericon-72-72.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/assets/graphicarts/android/android-launchericon-96-96.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
src/assets/graphicarts/favicon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
9
src/assets/graphicarts/favicon.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-anchor-favicon">
|
||||
<circle cx="12" cy="5" r="3" stroke-width="4" stroke="#ffffff"></circle>
|
||||
<line x1="12" y1="22" x2="12" y2="8" stroke-width="4" stroke="#ffffff"></line>
|
||||
<path d="M5 12H2a10 10 0 0 0 20 0h-3" stroke-width="4" stroke="#ffffff"></path>
|
||||
|
||||
<circle cx="12" cy="5" r="3"></circle>
|
||||
<line x1="12" y1="22" x2="12" y2="8"></line>
|
||||
<path d="M5 12H2a10 10 0 0 0 20 0h-3"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 603 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-more-vertical"><circle cx="12" cy="12" r="1"></circle><circle cx="12" cy="5" r="1"></circle><circle cx="12" cy="19" r="1"></circle></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-folder-minus"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path><line x1="9" y1="14" x2="15" y2="14"></line></svg>
|
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 361 B |
1
src/assets/graphicarts/folder-plus.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-folder-plus"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path><line x1="12" y1="11" x2="12" y2="17"></line><line x1="9" y1="14" x2="15" y2="14"></line></svg>
|
After Width: | Height: | Size: 405 B |
1
src/assets/graphicarts/globe.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-globe"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
|
After Width: | Height: | Size: 409 B |
Before Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 2.2 KiB |
BIN
src/assets/graphicarts/ios/100.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
src/assets/graphicarts/ios/1024.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
src/assets/graphicarts/ios/114.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
src/assets/graphicarts/ios/120.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
src/assets/graphicarts/ios/128.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
src/assets/graphicarts/ios/144.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
src/assets/graphicarts/ios/152.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
src/assets/graphicarts/ios/16.png
Normal file
After Width: | Height: | Size: 515 B |
BIN
src/assets/graphicarts/ios/167.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
src/assets/graphicarts/ios/180.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
src/assets/graphicarts/ios/192.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
src/assets/graphicarts/ios/20.png
Normal file
After Width: | Height: | Size: 699 B |
BIN
src/assets/graphicarts/ios/256.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src/assets/graphicarts/ios/29.png
Normal file
After Width: | Height: | Size: 939 B |
BIN
src/assets/graphicarts/ios/32.png
Normal file
After Width: | Height: | Size: 1010 B |
BIN
src/assets/graphicarts/ios/40.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/assets/graphicarts/ios/50.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/assets/graphicarts/ios/512.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
src/assets/graphicarts/ios/57.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/graphicarts/ios/58.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/graphicarts/ios/60.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/graphicarts/ios/64.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src/assets/graphicarts/ios/72.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/assets/graphicarts/ios/76.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/graphicarts/ios/80.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
src/assets/graphicarts/ios/87.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-list"><line x1="8" y1="6" x2="21" y2="6"></line><line x1="8" y1="12" x2="21" y2="12"></line><line x1="8" y1="18" x2="21" y2="18"></line><line x1="3" y1="6" x2="3.01" y2="6"></line><line x1="3" y1="12" x2="3.01" y2="12"></line><line x1="3" y1="18" x2="3.01" y2="18"></line></svg>
|
Before Width: | Height: | Size: 482 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-settings"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
|
Before Width: | Height: | Size: 1011 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-trash-2"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
|
Before Width: | Height: | Size: 448 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-trash"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
|
Before Width: | Height: | Size: 269 B After Width: | Height: | Size: 356 B |
BIN
src/assets/graphicarts/windows11/LargeTile.scale-100.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/graphicarts/windows11/LargeTile.scale-125.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/graphicarts/windows11/LargeTile.scale-150.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
src/assets/graphicarts/windows11/LargeTile.scale-200.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
src/assets/graphicarts/windows11/LargeTile.scale-400.png
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
src/assets/graphicarts/windows11/SmallTile.scale-100.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/assets/graphicarts/windows11/SmallTile.scale-125.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
src/assets/graphicarts/windows11/SmallTile.scale-150.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
src/assets/graphicarts/windows11/SmallTile.scale-200.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
src/assets/graphicarts/windows11/SmallTile.scale-400.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/graphicarts/windows11/SplashScreen.scale-100.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/graphicarts/windows11/SplashScreen.scale-125.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/graphicarts/windows11/SplashScreen.scale-150.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
src/assets/graphicarts/windows11/SplashScreen.scale-200.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
src/assets/graphicarts/windows11/SplashScreen.scale-400.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
src/assets/graphicarts/windows11/Square150x150Logo.scale-100.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
src/assets/graphicarts/windows11/Square150x150Logo.scale-125.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
src/assets/graphicarts/windows11/Square150x150Logo.scale-150.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
src/assets/graphicarts/windows11/Square150x150Logo.scale-200.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/graphicarts/windows11/Square150x150Logo.scale-400.png
Normal file
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 602 B |
After Width: | Height: | Size: 715 B |
After Width: | Height: | Size: 722 B |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.5 KiB |