mirror of
https://github.com/nkanaev/yarr.git
synced 2025-05-24 00:33:14 +00:00
initial fever api
This commit is contained in:
parent
54c2a6458d
commit
fcaf23d6bc
157
server/fever.go
Normal file
157
server/fever.go
Normal file
@ -0,0 +1,157 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/nkanaev/yarr/storage"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var feverHandlers = map[string]func(rw http.ResponseWriter, req *http.Request){
|
||||
"groups": FeverGroupsHandler,
|
||||
"feeds": FeverFeedsHandler,
|
||||
"unread_item_ids": FeverFilteredItemIDsHandler,
|
||||
"saved_item_ids": FeverFilteredItemIDsHandler,
|
||||
"links": FeverLinksHandler,
|
||||
}
|
||||
|
||||
type FeverGroup struct {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type FeverFeedsGroup struct {
|
||||
GroupID int64 `json:"group_id"`
|
||||
FeedIDs string `json:"feed_ids"`
|
||||
}
|
||||
|
||||
type FeverFeed struct {
|
||||
ID int64 `json:"id"`
|
||||
FaviconID int64 `json:"favicon_id"`
|
||||
Title string `json:"title"`
|
||||
Url string `json:"url"`
|
||||
SiteUrl string `json:"site_url"`
|
||||
IsSpark int `json:"is_spark"`
|
||||
LastUpdatedOnTime int64 `json:"last_updated_on_time"`
|
||||
}
|
||||
|
||||
func writeFeverJSON(rw http.ResponseWriter, data map[string]interface{}) {
|
||||
data["api_version"] = 1
|
||||
data["auth"] = 1
|
||||
writeJSON(rw, data)
|
||||
}
|
||||
|
||||
func FeverHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
query := req.URL.Query()
|
||||
fmt.Println(req.URL.String())
|
||||
for key, handler := range feverHandlers {
|
||||
if _, ok := query[key]; ok {
|
||||
handler(rw, req)
|
||||
return
|
||||
}
|
||||
}
|
||||
writeJSON(rw, map[string]interface{}{
|
||||
"api_version": 1,
|
||||
"auth": 1,
|
||||
})
|
||||
}
|
||||
|
||||
func joinInts(values []int64) string {
|
||||
var result strings.Builder
|
||||
for i, val := range values {
|
||||
fmt.Fprintf(&result, "%d", val)
|
||||
if i != len(values)-1 {
|
||||
result.WriteString(",")
|
||||
}
|
||||
}
|
||||
return result.String()
|
||||
}
|
||||
|
||||
func feedGroups(db *storage.Storage) []*FeverFeedsGroup {
|
||||
feeds := db.ListFeeds()
|
||||
|
||||
groupFeeds := make(map[int64][]int64)
|
||||
for _, feed := range feeds {
|
||||
// TODO: what about top-level feeds?
|
||||
if feed.FolderId == nil {
|
||||
continue
|
||||
}
|
||||
groupFeeds[*feed.FolderId] = append(groupFeeds[*feed.FolderId], feed.Id)
|
||||
}
|
||||
result := make([]*FeverFeedsGroup, 0)
|
||||
for groupId, feedIds := range groupFeeds {
|
||||
result = append(result, &FeverFeedsGroup{
|
||||
GroupID: groupId,
|
||||
FeedIDs: joinInts(feedIds),
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func FeverGroupsHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
folders := db(req).ListFolders()
|
||||
groups := make([]*FeverGroup, len(folders))
|
||||
for i, folder := range folders {
|
||||
groups[i] = &FeverGroup{ID: folder.Id, Title: folder.Title}
|
||||
}
|
||||
writeFeverJSON(rw, map[string]interface{}{
|
||||
"groups": groups,
|
||||
"feeds_groups": feedGroups(db(req)),
|
||||
})
|
||||
}
|
||||
|
||||
func FeverFeedsHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
feeds := db(req).ListFeeds()
|
||||
|
||||
feverFeeds := make([]*FeverFeed, len(feeds))
|
||||
for i, feed := range feeds {
|
||||
// TODO: check url/siteurl
|
||||
// TODO: store last updated on time?
|
||||
feverFeeds[i] = &FeverFeed{
|
||||
ID: feed.Id,
|
||||
FaviconID: feed.Id,
|
||||
Title: feed.Title,
|
||||
Url: feed.FeedLink,
|
||||
SiteUrl: feed.Link,
|
||||
IsSpark: 0,
|
||||
LastUpdatedOnTime: 1,
|
||||
}
|
||||
}
|
||||
writeFeverJSON(rw, map[string]interface{}{
|
||||
"feeds": feverFeeds,
|
||||
"feeds_groups": feedGroups(db(req)),
|
||||
})
|
||||
}
|
||||
|
||||
func FeverFilteredItemIDsHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
var status storage.ItemStatus
|
||||
var filter string
|
||||
if _, ok := req.URL.Query()["unread_item_ids"]; ok {
|
||||
status = storage.UNREAD
|
||||
filter = "unread_item_ids"
|
||||
} else {
|
||||
status = storage.STARRED
|
||||
filter = "saved_item_ids"
|
||||
}
|
||||
|
||||
itemIds := make([]int64, 0, 4000)
|
||||
batch := 1000
|
||||
index := 0
|
||||
for {
|
||||
items := db(req).ListItems(storage.ItemFilter{Status: &status}, index*batch, batch, true)
|
||||
if len(items) == 0 {
|
||||
break
|
||||
}
|
||||
for _, item := range items {
|
||||
itemIds = append(itemIds, item.Id)
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
writeFeverJSON(rw, map[string]interface{}{
|
||||
filter: joinInts(itemIds),
|
||||
})
|
||||
}
|
||||
|
||||
func FeverLinksHandler(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
}
|
@ -38,6 +38,7 @@ var routes []Route = []Route{
|
||||
p("/opml/import", OPMLImportHandler),
|
||||
p("/opml/export", OPMLExportHandler),
|
||||
p("/page", PageCrawlHandler),
|
||||
p("/fever/", FeverHandler),
|
||||
}
|
||||
|
||||
type asset struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user