Compare commits
No commits in common. "develop" and "v0.1.0" have entirely different histories.
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
.env
|
.env
|
||||||
sn-rss2tg
|
stackernews_rss-to-tg
|
||||||
sn-rss2tg.sqlite3
|
|
||||||
|
|||||||
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "sn-rss-to-tg",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
69
db.go
69
db.go
@ -1,69 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
db *sql.DB
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var err error
|
|
||||||
db, err = sql.Open("sqlite3", "sn-rss2tg.sqlite3")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
migrate(db)
|
|
||||||
}
|
|
||||||
|
|
||||||
func migrate(db *sql.DB) {
|
|
||||||
_, err := db.Exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS items (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
link TEXT NOT NULL,
|
|
||||||
pub_date TIMESTAMP WITH TIME ZONE NOT NULL
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("error during migration: %w", err)
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractIdFromItem(item Item) int {
|
|
||||||
parts := strings.Split(item.Guid, "/")
|
|
||||||
id, err := strconv.Atoi(parts[len(parts)-1])
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("error during item id extraction: %w", err)
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
func ItemExists(item Item) bool {
|
|
||||||
id := extractIdFromItem(item)
|
|
||||||
var count int
|
|
||||||
err := db.QueryRow(`SELECT COUNT(1) FROM items WHERE id = ?`, id).Scan(&count)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("error during item check: %w", err)
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
return count > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveItem(item Item) {
|
|
||||||
id := extractIdFromItem(item)
|
|
||||||
_, err := db.Exec(`INSERT INTO items(id, title, link, pub_date) VALUES (?, ?, ?, ?)`, id, item.Title, item.Link, item.PubDate.Time)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("error during item insert: %w", err)
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
3
go.mod
3
go.mod
@ -1,10 +1,9 @@
|
|||||||
module gitlab.com/ekzyis/sn-rss2tg
|
module gitlab.com/ekzyis/stackernews_rss-to-tg
|
||||||
|
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/joho/godotenv v1.5.1 // indirect
|
github.com/joho/godotenv v1.5.1 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.16 // indirect
|
|
||||||
github.com/namsral/flag v1.7.4-pre // indirect
|
github.com/namsral/flag v1.7.4-pre // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -2,7 +2,5 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
|||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
|
||||||
github.com/namsral/flag v1.7.4-pre h1:b2ScHhoCUkbsq0d2C15Mv+VU8bl8hAXV8arnWiOHNZs=
|
github.com/namsral/flag v1.7.4-pre h1:b2ScHhoCUkbsq0d2C15Mv+VU8bl8hAXV8arnWiOHNZs=
|
||||||
github.com/namsral/flag v1.7.4-pre/go.mod h1:OXldTctbM6SWH1K899kPZcf65KxJiD7MsceFUpB5yDo=
|
github.com/namsral/flag v1.7.4-pre/go.mod h1:OXldTctbM6SWH1K899kPZcf65KxJiD7MsceFUpB5yDo=
|
||||||
|
|||||||
23
main.go
23
main.go
@ -7,13 +7,25 @@ import (
|
|||||||
|
|
||||||
func WaitUntilNextUpdate() {
|
func WaitUntilNextUpdate() {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
dur := now.Truncate(time.Minute).Add(time.Minute).Sub(now)
|
dur := now.Truncate(time.Hour).Add(time.Hour).Sub(now)
|
||||||
log.Println("sleeping for", dur.Round(time.Second))
|
log.Println("sleeping for", dur.Round(time.Second))
|
||||||
time.Sleep(dur)
|
time.Sleep(dur)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func contains(rss *Rss, a Item) bool {
|
||||||
|
if rss == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, x := range rss.Channel.Items {
|
||||||
|
if x.Title == a.Title {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
defer db.Close()
|
var oldRss *Rss
|
||||||
for {
|
for {
|
||||||
rss, err := FetchStackerNewsRssFeed()
|
rss, err := FetchStackerNewsRssFeed()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -23,8 +35,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range rss.Channel.Items {
|
for _, item := range rss.Channel.Items {
|
||||||
if ItemExists(item) {
|
// TODO: We ignore errors during sending items to telegram.
|
||||||
log.Printf("item %s already exists. skipping.\n", item.Guid)
|
// This means these items will be missed since they will be skipped in the next run
|
||||||
|
if contains(oldRss, item) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := SendItemToTelegram(&item)
|
err := SendItemToTelegram(&item)
|
||||||
@ -32,9 +45,9 @@ func main() {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
SaveItem(item)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oldRss = rss
|
||||||
WaitUntilNextUpdate()
|
WaitUntilNextUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
rss.go
5
rss.go
@ -14,7 +14,6 @@ type Item struct {
|
|||||||
Link string `xml:"link"`
|
Link string `xml:"link"`
|
||||||
Description string `xml:"description"`
|
Description string `xml:"description"`
|
||||||
PubDate RssDate `xml:"pubDate"`
|
PubDate RssDate `xml:"pubDate"`
|
||||||
Author Author `xml:"author"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
@ -33,10 +32,6 @@ type RssDate struct {
|
|||||||
time.Time
|
time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type Author struct {
|
|
||||||
Name string `xml:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *RssDate) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
func (c *RssDate) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
var v string
|
var v string
|
||||||
dateFormat := "Mon, 02 Jan 2006 15:04:05 GMT"
|
dateFormat := "Mon, 02 Jan 2006 15:04:05 GMT"
|
||||||
|
|||||||
2
tg.go
2
tg.go
@ -33,7 +33,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SendItemToTelegram(item *Item) error {
|
func SendItemToTelegram(item *Item) error {
|
||||||
text := fmt.Sprintf("%s\n_%s by_ [%s](https://stacker.news/%s)\n", item.Title, humanize.Time(item.PubDate.Time), item.Author.Name, item.Author.Name)
|
text := fmt.Sprintf("%s (%s)\n", item.Title, humanize.Time(item.PubDate.Time))
|
||||||
linkItem := item.Link != item.Guid
|
linkItem := item.Link != item.Guid
|
||||||
if linkItem {
|
if linkItem {
|
||||||
text += fmt.Sprintf("[Link](%s) ", item.Link)
|
text += fmt.Sprintf("[Link](%s) ", item.Link)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user