Skip to content

Instantly share code, notes, and snippets.

@inhies
Last active December 8, 2019 19:23
Show Gist options
  • Save inhies/5125389 to your computer and use it in GitHub Desktop.
Save inhies/5125389 to your computer and use it in GitHub Desktop.
Reads the public feed from socialno.de every 60 seconds and displays the new posts with proper formatting to fit your terminal width. Usage: `go run socialnode.go`
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sort"
"strings"
"syscall"
"time"
"unsafe"
)
// Replace socialno.de with twitter.com if it suits you better
// You can also get user_timeline.json?screen_name=USERNAMEHERE
// Where USERNAMEHERE is, of course, the username of the person
var Config = Configuration{
FetchURL: "http://socialno.de/api/statuses/public_timeline.json",
RefreshInterval: 60, // In seconds
}
type Feed struct {
Posts Posts
}
type Post struct {
CreatedAt string `json:"created_at"`
ID int `json:"id"`
StatusnetConversationID int `json:"statusnet_conversation_id"`
Text string `json:"text"`
User User `json:"user"`
Truncated bool `json:"truncated"`
}
type User struct {
Name string `json:"name"`
ID int `json:"id"`
}
type Configuration struct {
FetchURL string
RefreshInterval int
}
type winsize struct {
Row uint16
Col uint16
Xpixel uint16
Ypixel uint16
}
type Posts []*Post
func (s Posts) Len() int { return len(s) }
func (s Posts) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type ByID struct{ Posts }
func (s ByID) Less(i, j int) bool { return s.Posts[i].ID < s.Posts[j].ID }
func init() {
fmt.Print("\033[?25l") // Hide the cursor
}
func main() {
var lastID int
for {
Connect:
response, err := http.Get(Config.FetchURL)
if err != nil {
fmt.Println("Error connecting to", Config.FetchURL, ", trying again")
goto Connect
}
bits, err := ioutil.ReadAll(response.Body)
response.Body.Close()
feed := &Feed{}
feedData := feed.Posts
err = json.Unmarshal(bits, &feedData)
if err != nil {
fmt.Println("Error reading from", Config.FetchURL, ", re-connecting")
goto Connect
}
sort.Sort(ByID{feedData})
termSize, err := GetWinsize()
if err != nil {
fmt.Println(err)
}
for _, post := range feedData {
if lastID < post.ID {
indent := len(post.User.Name) + 2
maxLen := int(termSize.Col - uint16(indent) - 1)
words := strings.Split(post.Text, " ")
fmt.Print(post.User.Name + ": ")
for wordCount, charsLeft := 0,
maxLen; wordCount < len(words); wordCount++ {
word := words[wordCount]
if charsLeft > len(word)+1 {
fmt.Print(word + " ")
charsLeft -= (len(word) + 1)
} else if charsLeft == len(word) {
fmt.Print(word + "\n")
fmt.Print(strings.Repeat(" ", indent))
charsLeft = maxLen
} else {
fmt.Print("\n")
fmt.Print(strings.Repeat(" ", indent))
fmt.Print(word + " ")
charsLeft = maxLen - (len(word) + 1)
}
}
fmt.Print("\n\n")
lastID = post.ID
}
}
// Spinning cursor while we wait
chars := [4]byte{'|', '/', '-', '\\'}
for i := 4; i <= Config.RefreshInterval+4; i++ {
fmt.Print("\b" + string(chars[i%4]))
time.Sleep(1 * time.Second)
}
fmt.Print("\b")
}
}
func GetWinsize() (*winsize, error) {
ws := new(winsize)
r1, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
uintptr(syscall.Stdin),
uintptr(syscall.TIOCGWINSZ),
uintptr(unsafe.Pointer(ws)),
)
if int(r1) == -1 {
return nil, fmt.Errorf("GetWinsize", int(errno))
}
return ws, nil
}
@gwenbell
Copy link

gwenbell commented Mar 9, 2013

Did it. Works like a charm. Thanks, inhies

Submitted to Pinboard: https://pinboard.in/u:gwenbell/b:296b87d44b61

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment