Skip to content

Commit aea9e64

Browse files
committed
add dockerfile
1 parent dab00e6 commit aea9e64

12 files changed

Lines changed: 154 additions & 108 deletions

File tree

Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM alpine:3.20
2+
3+
RUN apk add --no-cache ca-certificates
4+
COPY bin/reader-linux-amd64 /usr/local/bin/reader
5+
6+
EXPOSE 8080
7+
CMD ["reader", "-d", "/data"]

Makefile

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@ build:
66
GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o ${BINARY_NAME}-linux-amd64
77
GOARCH=amd64 GOOS=windows go build -ldflags="-s -w" -o ${BINARY_NAME}-windows-amd64.exe
88

9+
docker:
10+
docker compose build
11+
12+
docker-run:
13+
docker compose up -d
14+
15+
docker-stop:
16+
docker compose down
17+
918
clean:
1019
go clean
11-
rm ${BINARY_NAME}-darwin-arm64
12-
rm ${BINARY_NAME}-darwin-amd64
13-
rm ${BINARY_NAME}-linux-amd64
14-
rm ${BINARY_NAME}-windows-x64.exe
20+
rm -f ${BINARY_NAME}-darwin-arm64 ${BINARY_NAME}-darwin-amd64 ${BINARY_NAME}-linux-amd64 ${BINARY_NAME}-windows-x64.exe
21+
22+
.PHONY: build docker docker-run docker-stop clean

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ The server comes with a built-in, minimal web UI for easy feed management.
1414

1515
### Fever API Support
1616

17-
FeedReader supports the [Fever API](https://github.com/song940/fever-go), enabling integration with various RSS client apps.
17+
FeedReader supports the [Fever API](https://github.com/lsongdev/fever-go), enabling integration with various RSS client apps.
1818

1919
![Fever API](./screenshots/app.jpg)
2020

@@ -28,7 +28,7 @@ FeedReader supports the [Fever API](https://github.com/song940/fever-go), enabli
2828
To install FeedReader, run the following commands in your terminal:
2929

3030
```shell
31-
curl -L https://github.com/song940/feedreader/releases/download/<tag>/reader-linux-$(uname -m) -o /usr/local/bin/feedreader
31+
curl -L https://github.com/lsongdev/feedreader/releases/download/<tag>/reader-linux-$(uname -m) -o /usr/local/bin/feedreader
3232
chmod +x /usr/local/bin/feedreader
3333
```
3434

@@ -37,7 +37,7 @@ Then, create a systemd service file for FeedReader:
3737
```ini
3838
[Unit]
3939
Description=FeedReader - A Self-hosted RSS Feed Aggregator Service
40-
Documentation=https://github.com/song940/feedreader
40+
Documentation=https://github.com/lsongdev/feedreader
4141
After=network-online.target
4242
Wants=network-online.target systemd-networkd-wait-online.service
4343

docker-compose.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
services:
2+
feedreader:
3+
build: .
4+
ports:
5+
- "7789:8080"
6+
volumes:
7+
- ~/.feedreader:/data
8+
restart: unless-stopped

main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package main
22

33
import (
4+
"flag"
45
"net/http"
56

67
"github.com/lsongdev/feedreader/reader"
78
"github.com/song940/fever-go/fever"
89
)
910

1011
func main() {
12+
13+
flag.StringVar(&reader.ConfigDir, "d", "~/.feedreader", "")
14+
flag.Parse()
15+
1116
config := reader.NewConfig()
1217
config.Load()
1318

reader/config.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package reader
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"strings"
7+
8+
"gopkg.in/yaml.v2"
9+
)
10+
11+
func expandHomeDir(path string) string {
12+
if strings.HasPrefix(path, "~/") {
13+
return filepath.Join(os.Getenv("HOME"), path[2:])
14+
}
15+
return path
16+
}
17+
18+
var ConfigDir = filepath.Join(os.Getenv("HOME"), ".feedreader")
19+
20+
type Config struct {
21+
Title string `json:"title" yaml:"title"`
22+
Listen string `json:"listen" yaml:"listen"`
23+
Users []User `json:"users" yaml:"users"`
24+
}
25+
26+
func NewConfig() *Config {
27+
return &Config{
28+
Title: "Reader",
29+
Listen: "0.0.0.0:8080",
30+
Users: []User{{"admin", "admin123"}},
31+
}
32+
}
33+
34+
func (conf *Config) Load() error {
35+
ConfigDir = expandHomeDir(ConfigDir)
36+
filename := filepath.Join(ConfigDir, "config.yaml")
37+
if _, err := os.Stat(filename); os.IsNotExist(err) {
38+
return err
39+
}
40+
data, err := os.ReadFile(filename)
41+
if err != nil {
42+
return err
43+
}
44+
return yaml.Unmarshal(data, &conf)
45+
}

reader/reader.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"log"
77
"os"
88
"path"
9+
"path/filepath"
910
"strings"
1011
"time"
1112

@@ -51,9 +52,9 @@ type Reader struct {
5152
// New initializes a new instance of the Reader application.
5253
func NewReader(config *Config) (reader *Reader, err error) {
5354
// Open a database connection
54-
file := path.Join(config.Dir, "reader.db")
55+
file := path.Join(expandHomeDir(ConfigDir), "reader.db")
5556
if _, err := os.Stat(file); os.IsNotExist(err) {
56-
os.MkdirAll(config.Dir, 0755)
57+
os.MkdirAll(filepath.Dir(file), 0755)
5758
}
5859
db, err := sql.Open("sqlite", file)
5960
if err != nil {

reader/server.go

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,51 +9,20 @@ import (
99
"log"
1010
"net/http"
1111
"net/url"
12-
"os"
13-
"path/filepath"
1412
"strconv"
1513
"time"
1614

1715
"github.com/lsongdev/feedreader/feed"
1816
"github.com/lsongdev/feedreader/templates"
19-
"gopkg.in/yaml.v2"
2017
)
2118

22-
type H map[string]interface{}
19+
type H map[string]any
2320

2421
type User struct {
2522
Username string `json:"username"`
2623
Password string `json:"password"`
2724
}
2825

29-
type Config struct {
30-
Dir string `json:"-" yaml:"-"`
31-
Title string `json:"title" yaml:"title"`
32-
Listen string `json:"listen" yaml:"listen"`
33-
Users []User `json:"users" yaml:"users"`
34-
Stylesheet string `json:"stylesheet" yaml:"stylesheet"`
35-
}
36-
37-
func NewConfig() *Config {
38-
return &Config{
39-
Title: "Reader",
40-
Listen: "0.0.0.0:8080",
41-
Users: []User{{"admin", "admin123"}},
42-
}
43-
}
44-
45-
func (conf *Config) Load() error {
46-
filename := filepath.Join(conf.Dir, "config.yaml")
47-
if _, err := os.Stat(filename); os.IsNotExist(err) {
48-
return err
49-
}
50-
data, err := os.ReadFile(filename)
51-
if err != nil {
52-
return err
53-
}
54-
return yaml.Unmarshal(data, &conf)
55-
}
56-
5726
type Pagination struct {
5827
Page int
5928
Size int
@@ -101,7 +70,7 @@ func (reader *Reader) Render(w http.ResponseWriter, templateName string, data H)
10170
data = H{}
10271
}
10372
data["AppName"] = reader.config.Title
104-
data["Stylesheet"] = template.CSS(reader.config.Stylesheet)
73+
// data["Stylesheet"] = template.CSS(reader.config.Stylesheet)
10574
// tmpl, err := template.ParseFiles("templates/layout.html", "templates/"+templateName+".html")
10675
// Parse templates from embedded file system
10776
tmpl, err := template.New("").ParseFS(templates.Files, "layout.html", templateName+".html")
@@ -443,20 +412,28 @@ func (reader *Reader) PostsJson(w http.ResponseWriter, r *http.Request) {
443412
}
444413

445414
func (reader *Reader) CategoryView(w http.ResponseWriter, r *http.Request) {
446-
if r.Method != "POST" {
447-
return
448-
}
449-
r.ParseForm()
450-
if !reader.CheckAuth(w, r) {
415+
if r.Method == "POST" {
416+
r.ParseForm()
417+
if !reader.CheckAuth(w, r) {
418+
return
419+
}
420+
categoryName := r.FormValue("name")
421+
_, err := reader.CreateCategory(categoryName)
422+
if err != nil {
423+
reader.Error(w, err)
424+
return
425+
}
426+
http.Redirect(w, r, "/categories", http.StatusFound)
451427
return
452428
}
453-
categoryName := r.FormValue("name")
454-
categoryId, err := reader.CreateCategory(categoryName)
429+
categories, err := reader.GetCategories()
455430
if err != nil {
456431
reader.Error(w, err)
457432
return
458433
}
459-
http.Redirect(w, r, fmt.Sprintf("/posts?category=%d", categoryId), http.StatusFound)
434+
reader.Render(w, "categories", H{
435+
"categories": categories,
436+
})
460437
}
461438

462439
func (reader *Reader) RefreshView(w http.ResponseWriter, r *http.Request) {

templates/categories.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{define "page"}}
2+
3+
<h2>Categories</h2>
4+
5+
<form method="post" action="/categories">
6+
<div class="form-field">
7+
<label for="name">Category Name:</label>
8+
<input type="text" name="name" placeholder="Category Name" required class="input">
9+
</div>
10+
<div class="form-field">
11+
<input type="submit" value="Create" class="button">
12+
</div>
13+
</form>
14+
15+
<ul class="list">
16+
{{range .categories}}
17+
<li>{{.Name}}</li>
18+
{{end}}
19+
</ul>
20+
{{end}}

templates/layout.html

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,6 @@
1414
padding: 0;
1515
}
1616

17-
.container {
18-
padding: 10px 30px 100px 30px;
19-
}
20-
21-
.form-field {
22-
margin-bottom: 5px;
23-
}
24-
2517
article {
2618
overflow: hidden;
2719
white-space: wrap;
@@ -31,13 +23,6 @@
3123
color: red;
3224
}
3325
</style>
34-
<style>
35-
{
36-
{
37-
.Stylesheet
38-
}
39-
}
40-
</style>
4126
</head>
4227

4328
<body>
@@ -46,6 +31,7 @@ <h1><a href="/">{{.AppName}}</a></h1>
4631
<nav>
4732
<a href="/posts">posts</a>
4833
<a href="/feeds">feeds</a>
34+
<a href="/categories">categories</a>
4935
<a href="/new">[+]</a>
5036
<a href="/rss.xml">[rss]</a>
5137
<a href="/atom.xml">[atom]</a>

0 commit comments

Comments
 (0)