-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Squashed commit of the following: commit 3382b02 Author: azimut <[email protected]> Date: Fri Apr 28 12:41:42 2023 -0300 discourse: dramatic author names commit 5ce96e2 Author: azimut <[email protected]> Date: Fri Apr 28 12:25:11 2023 -0300 discourse: add comment tree graph commit c04461a Author: azimut <[email protected]> Date: Fri Apr 28 10:30:34 2023 -0300 readme: update reddit desc commit ff92224 Author: azimut <[email protected]> Date: Fri Apr 28 10:29:40 2023 -0300 discourse: add working tui/cli, missing comments tree graph
- Loading branch information
Showing
17 changed files
with
476 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"flag" | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
"time" | ||
|
||
"github.com/azimut/cli-view/internal/discourse" | ||
"github.com/azimut/cli-view/internal/tui" | ||
"github.com/fatih/color" | ||
) | ||
|
||
type options struct { | ||
leftPadding uint | ||
timeout time.Duration | ||
useColors bool | ||
showAuthor bool | ||
showDate bool | ||
showId bool | ||
userAgent string | ||
useTUI bool | ||
width uint | ||
} | ||
|
||
var opts options | ||
|
||
func init() { | ||
flag.BoolVar(&opts.useColors, "C", true, "use colors") | ||
flag.BoolVar(&opts.showDate, "d", false, "print date on comments") | ||
flag.BoolVar(&opts.showAuthor, "a", true, "print author on comments") | ||
flag.BoolVar(&opts.useTUI, "x", false, "use TUI") | ||
flag.DurationVar(&opts.timeout, "t", time.Second*5, "timeout in seconds") | ||
flag.StringVar(&opts.userAgent, "A", "DiscourseView/1.0", "user agent to send") | ||
flag.UintVar(&opts.width, "w", 100, "terminal width") | ||
flag.UintVar(&opts.leftPadding, "l", 3, "left padding on comments") | ||
} | ||
|
||
func usage() { | ||
fmt.Printf("Usage: %s [OPTIONS] URL ...\n", os.Args[0]) | ||
flag.PrintDefaults() | ||
} | ||
|
||
func run(args []string, stdout io.Writer) error { | ||
flag.Parse() | ||
flag.Usage = usage | ||
color.NoColor = !opts.useColors | ||
if flag.NArg() != 1 { | ||
flag.Usage() | ||
return errors.New("missing URL argument") | ||
} | ||
|
||
url := flag.Args()[0] | ||
thread, err := discourse.Fetch(url, opts.userAgent, opts.timeout) | ||
if err != nil { | ||
return errors.New("could not fetch url") | ||
} | ||
thread.Width = int(opts.width) | ||
thread.LeftPadding = int(opts.leftPadding) | ||
thread.ShowAuthor = opts.showAuthor | ||
thread.ShowDate = opts.showDate | ||
|
||
if opts.useTUI { | ||
tui.RenderLoop(discourse.NewProgram(*thread)) | ||
} else { | ||
fmt.Println(thread) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func main() { | ||
err := run(os.Args, os.Stdout) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package discourse | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/azimut/cli-view/internal/fetch" | ||
) | ||
|
||
func Fetch(rawUrl, userAgent string, timeout time.Duration) (*Thread, error) { | ||
url, err := effectiveUrl(rawUrl) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
rawJson, err := fetch.Fetch(url, userAgent, timeout) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
thread, err := toThread(rawJson, rawUrl) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return thread, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package discourse | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
"github.com/dustin/go-humanize" | ||
) | ||
|
||
func TestFetch(t *testing.T) { | ||
testUrl := "https://users.rust-lang.org/t/forum-code-formatting-and-syntax-highlighting/42214" | ||
thread, err := Fetch(testUrl, "Mozilla", time.Second*5) | ||
if err != nil { | ||
t.Fail() | ||
} | ||
got := thread.id | ||
expected := 42214 | ||
if got != expected { | ||
fmt.Println(thread) | ||
fmt.Println(humanize.Time(thread.op.createdAt)) | ||
t.Errorf("got %d expected %d", got, expected) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package discourse | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/azimut/cli-view/internal/format" | ||
"github.com/charmbracelet/lipgloss" | ||
"github.com/dustin/go-humanize" | ||
) | ||
|
||
var authorStyle = lipgloss.NewStyle(). | ||
Bold(true). | ||
Background(lipgloss.Color("8")). | ||
Foreground(lipgloss.Color("0")) | ||
|
||
func (t Thread) String() (ret string) { | ||
ret += fmt.Sprint(t.op) | ||
for _, comment := range t.comments { | ||
ret += fmt.Sprint(comment) | ||
ret += "\n" | ||
} | ||
return | ||
} | ||
|
||
func (o Op) String() (ret string) { | ||
ret += fmt.Sprintf("title: %s\n", o.title) | ||
ret += fmt.Sprintf(" self: %s\n", o.thread.url) | ||
ret += fmt.Sprintf( | ||
"\n%s\n\n", | ||
format.FormatHtml2Text(o.message, o.thread.Width, o.thread.LeftPadding), | ||
) | ||
ret += fmt.Sprintf("%s - %s \n\n\n", authorStyle.Render(o.author), humanize.Time(o.createdAt)) | ||
return | ||
} | ||
|
||
func (c Comment) String() (ret string) { | ||
ret += fmt.Sprintf( | ||
"%s\n", | ||
format.FormatHtml2Text(c.message, c.thread.Width, c.thread.LeftPadding*c.depth+1), | ||
) | ||
ret += strings.Repeat(" ", c.depth*c.thread.LeftPadding) | ||
ret += ">>" | ||
if c.thread.ShowAuthor { | ||
ret += " " | ||
if c.author == c.thread.op.author { | ||
ret += authorStyle.Render(c.author) | ||
} else { | ||
ret += c.author | ||
} | ||
} | ||
if c.thread.ShowDate { | ||
ret += " " + humanize.Time(c.createdAt) | ||
} | ||
ret += "\n\n" | ||
for _, reply := range c.replies { | ||
ret += fmt.Sprint(reply) | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package discourse | ||
|
||
import ( | ||
"errors" | ||
|
||
"github.com/tidwall/gjson" | ||
) | ||
|
||
func toThread(rawJson, rawUrl string) (*Thread, error) { | ||
if !gjson.Valid(rawJson) { | ||
return nil, errors.New("invalid json response") | ||
} | ||
parsedJson := gjson.Parse(rawJson) | ||
|
||
var thread Thread | ||
thread.id = int(parsedJson.Get("id").Int()) | ||
thread.url = rawUrl | ||
|
||
op := toOp(parsedJson) | ||
op.thread = &thread | ||
thread.op = op | ||
|
||
rawComments := parsedJson.Get("post_stream.posts").Array()[1:] | ||
for _, rawComment := range rawComments { | ||
if isAnAction(rawComment) { | ||
continue | ||
} | ||
comment := toComment(rawComment) | ||
comment.thread = &thread | ||
thread.insertComment(comment) | ||
} | ||
|
||
return &thread, nil | ||
} | ||
|
||
func isAnAction(result gjson.Result) bool { | ||
return result.Get("cooked").String() == "" && result.Get("action_code").String() != "" | ||
} | ||
|
||
func toOp(resultJson gjson.Result) Op { | ||
resultOp := resultJson.Get("post_stream.posts.0") | ||
return Op{ | ||
id: int(resultOp.Get("post_number").Int()), | ||
author: resultOp.Get("username").String(), | ||
message: resultOp.Get("cooked").String(), | ||
createdAt: resultJson.Get("created_at").Time(), | ||
title: resultJson.Get("title").String(), | ||
} | ||
} | ||
|
||
func toComment(resultComment gjson.Result) Comment { | ||
// TODO: depth, replies | ||
return Comment{ | ||
author: resultComment.Get("username").String(), | ||
createdAt: resultComment.Get("created_at").Time(), | ||
id: int(resultComment.Get("post_number").Int()), | ||
message: resultComment.Get("cooked").String(), | ||
parentId: int(resultComment.Get("reply_to_post_number").Int()), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package discourse | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"testing" | ||
) | ||
|
||
func TestToThread(t *testing.T) { | ||
testUrl := "https://users.rust-lang.org/t/forum-code-formatting-and-syntax-highlighting/42214/2" | ||
testFile := "../../testdata/discourse-42214.json" | ||
rawJson, err := ioutil.ReadFile(testFile) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
thread, err := toThread(string(rawJson), testUrl) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
fmt.Println(thread) // DEBUG | ||
|
||
got := thread.id | ||
expected := 42214 | ||
if expected != got { | ||
t.Errorf("got %d expected %d", got, expected) | ||
} | ||
|
||
got = thread.op.id | ||
expected = 1 | ||
if expected != got { | ||
t.Errorf("got %d expected %d", got, expected) | ||
} | ||
|
||
got = len(thread.comments) | ||
expected = 3 | ||
if expected != got { | ||
t.Errorf("got %d expected %d", got, expected) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package discourse | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/azimut/cli-view/internal/tui" | ||
tea "github.com/charmbracelet/bubbletea" | ||
) | ||
|
||
const rightPadding = 10 | ||
|
||
type Model struct { | ||
render tui.Model | ||
Thread | ||
} | ||
|
||
func NewProgram(thread Thread) *tea.Program { | ||
return tea.NewProgram(Model{Thread: thread}, | ||
tea.WithAltScreen()) | ||
} | ||
|
||
func (m Model) Init() tea.Cmd { | ||
return nil | ||
} | ||
|
||
func (m Model) View() string { | ||
return m.render.View() | ||
} | ||
|
||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { | ||
var cmd tea.Cmd | ||
// Initialize data to be used for links scrapping | ||
if m.render.RawContent == "" { | ||
m.Width = 300 | ||
m.render.RawContent = fmt.Sprint(m) | ||
} | ||
m.render, cmd = m.render.Update(msg) | ||
switch msg := msg.(type) { | ||
case tea.WindowSizeMsg: | ||
m.Width = msg.Width - rightPadding | ||
m.render.Viewport.SetContent(fmt.Sprint(m)) | ||
} | ||
return m, cmd | ||
} |
Oops, something went wrong.