Skip to content

Commit

Permalink
fix makefile + .gitignore bins + fourchan graph mostly complete
Browse files Browse the repository at this point in the history
missing add depth field and other formatting of messages
  • Loading branch information
azimut committed Apr 18, 2023
1 parent b3c1058 commit 8b23614
Show file tree
Hide file tree
Showing 9 changed files with 327 additions and 17 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
twitterview
hackerview
redditview
fourchanview

# Created by https://www.toptal.com/developers/gitignore/api/go
# Edit at https://www.toptal.com/developers/gitignore?templates=go
Expand Down
15 changes: 6 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
GO_FILES = $(shell find . -type f -name '*.go')
GO_FILES := $(shell find . -type f -name '*.go')
BINARIES := twitterview hackerview redditview fourchanview

.PHONY: all install clean test

all: twitterview hackerview redditview
all: $(BINARIES)

hackerview:
redditview:
twitterview: $(GO_FILES)
$(BINARIES): $(GO_FILES)
go build -v -ldflags="-s -w" ./cmd/$@
ls -lh $@

install: hackerview twitterview redditview
mv hackerview $(HOME)/go/bin/
mv twitterview $(HOME)/go/bin/
mv redditview $(HOME)/go/bin/
install: $(BINARIES);
mv $(BINARIES) $(HOME)/go/bin/

clean: ; go clean -x ./...
test: ; go test -vet=all -v -race ./...
57 changes: 57 additions & 0 deletions cmd/fourchanview/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import (
"errors"
"flag"
"fmt"
"io"
"log"
"os"
"time"

"github.com/azimut/cli-view/internal/fourchan"
"github.com/fatih/color"
)

type options struct {
timeout time.Duration
useColors bool
userAgent string
width int
}

var opts options

func init() {
flag.BoolVar(&opts.useColors, "C", true, "use colors")
flag.IntVar(&opts.width, "w", 80, "fixed with") // TODO: use opts.width
}

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 := fourchan.Fetch(url)
if err != nil {
return err
}
fmt.Println(thread)
return nil
}

func main() {
err := run(os.Args, os.Stdout)
if err != nil {
log.Fatal(err)
}
}
2 changes: 1 addition & 1 deletion internal/fourchan/TODO.org
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
- Types of messages
- [ ] Code embed <pre class=prettyprint", could be inlined
- [ ] Code embed *<pre class=prettyprint"*, could be inlined
#+begin_src html
<a href=\"#p92788773\" class=\"quotelink\">&gt;&gt;92788773</a><br>
<span class=\"quote\">&gt;In the first one, you&#039;re passing i a dictionary that matches the keyword arguments of the function, so it works.</span><br>
Expand Down
9 changes: 6 additions & 3 deletions internal/fourchan/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,24 @@ func (post Post) String() (ret string) {
}

if post.attachment.filename == "" {
ret += fmt.Sprintf(">> %13s", humanize.Time(post.created))
ret += fmt.Sprintf(">> %-13s", humanize.Time(post.created))
} else {
if strings.HasSuffix(post.attachment.url, post.attachment.filename) {
ret += fmt.Sprintf(">> %13s | %s | %s",
ret += fmt.Sprintf(">> %-13s | %s | %s",
humanize.Time(post.created),
post.attachment.url,
post.attachment.filename,
)
} else {
ret += fmt.Sprintf(">> %13s | %s",
ret += fmt.Sprintf(">> %-13s | %s",
humanize.Time(post.created),
post.attachment.url,
)
}
}
for _, reply := range post.replies {
ret += fmt.Sprint(reply)
}
ret += "\n\n"
return
}
98 changes: 95 additions & 3 deletions internal/fourchan/parse.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
package fourchan

import "github.com/moshee/go-4chan-api/api"
import (
"fmt"
"regexp"
"strconv"
"strings"

"github.com/moshee/go-4chan-api/api"
)

var reQuote = regexp.MustCompile(`<a href="[^"]+" class="quotelink">&gt;&gt;[0-9]+</a>[ ]*<br>`)

func toThread(apiThread *api.Thread) *Thread {
thread := Thread{
Expand All @@ -19,16 +28,90 @@ func toThread(apiThread *api.Thread) *Thread {
}
// TODO: depth + replies tree
for _, apiPost := range apiThread.Posts[1:] {
post := Post{
newPost := Post{
attachment: getAttachment(apiPost),
comment: apiPost.Comment,
created: apiPost.Time,
id: int(apiPost.Id),
parentId: thread.op.id,
subject: apiPost.Subject,
}
for _, post := range explodePost(newPost) {
thread.insert(post)
}
thread.posts = append(thread.posts, post)
}
return &thread
}

// explodePost explodes based on "quotelink"
func explodePost(post Post) (posts []Post) {
findings := reQuote.FindAllString(post.comment, -1)
replies := reQuote.Split(post.comment, -1)

// Whole post is "not replying"
if len(findings) == 0 {
return append(posts, post)
}

// At least part of the post is "not replying"
if len(replies) > 0 && replies[0] != "" {
newPost := post
newPost.comment = replies[0]
posts = append(posts, newPost)
}

// Remove (by now processed) not reply part
replies = replies[1:]
if len(replies) == 0 {
return
}

// Add simple 1/1 reply/comment
if (!containsEmptyString(replies)) && len(replies) == len(findings) {
for i, reply := range replies {
id := getParentId(findings[i])
if id == 0 {
continue // TODO: handle external links?
}
newPost := post
newPost.comment = reply
newPost.parentId = id
posts = append(posts, newPost)
}
return
}

fmt.Println("---- Findings ", len(findings))
for _, finding := range findings {
fmt.Println(finding)
}
fmt.Println("---- Comment <" + post.subject + ">")
fmt.Println(post.comment)
fmt.Println("---- Replies ", len(replies))
for _, reply := range replies {
fmt.Println("'" + reply + "'")
}
fmt.Println("--------------------------------------------------")
return
}

func getParentId(finding string) int {
if strings.Contains(finding, `/g/thread/`) {
return 0
}
begin := strings.Index(finding, "#p")
if begin == -1 {
return 0
}
rawId := finding[begin+2:]
rawId = rawId[0:strings.Index(rawId, `"`)]
id, err := strconv.Atoi(rawId)
if err != nil {
return 0
}
return id
}

func getAttachment(post *api.Post) Attachment {
if post.ImageURL() == "" {
return Attachment{}
Expand All @@ -38,3 +121,12 @@ func getAttachment(post *api.Post) Attachment {
filename: post.File.Name + post.File.Ext,
}
}

func containsEmptyString(xs []string) bool {
for _, x := range xs {
if x == "" {
return true
}
}
return false
}
116 changes: 116 additions & 0 deletions internal/fourchan/parse_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package fourchan

import (
"testing"
"time"

"github.com/moshee/go-4chan-api/api"
)

var testOp = &api.Post{
Comment: "OP plaintext",
Id: 92834152,
Subject: "my op subject",
Time: time.Now(),
}

var testThread = &api.Thread{
Board: "g",
OP: testOp,
Posts: []*api.Post{
testOp,
{
Subject: "same thread SINGLE reply (to OP) and a link",
Comment: `<a href="#p92834152" class="quotelink">&gt;&gt;92834152</a><br>Yes https://jetbra.in/s`,
Id: 92835905,
Time: time.Now(),
// File: &api.File{
// Ext: ".jpg",
// Name: "1653870571633",
// },
},
// PLACEHOLDER FOR ONE THAT has an empty comment, AND only has an attachment
// {
// Subject: "same thread SINGLE reply and a link",
// Comment: ``,
// Id: 92835905,
// Time: time.Now(),
// File: &api.File{
// Ext: ".jpg",
// Name: "1653870571633",
// },
// },
{
Subject: "same thread SINGLE reply, and non linked reply to OP",
Comment: `No YOU<br><br><a href="#p92835905" class="quotelink">&gt;&gt;92835905</a><br>Yes https://jetbra.in/s`,
Id: 92835911,
Time: time.Now(),
},
{
Subject: "plaintext comment",
Comment: "hey whats up",
Id: 92838633,
Time: time.Now(),
},
{
Subject: "same thread 2 replies",
Comment: `<a href="#p92834152" class="quotelink">&gt;&gt;92834152</a><br>paying for free software?<br><br><a href="#p92835905" class="quotelink">&gt;&gt;92835905</a><br>based`,
Id: 92838617,
Time: time.Now(),
},
{
Subject: "same thread 2 replies, with the same message ",
Comment: `<a href="#p92834152" class="quotelink">&gt;&gt;92834152</a><br><a href="#p92835905" class="quotelink">&gt;&gt;92835905</a><br>based`,
Id: 92838699,
Time: time.Now(),
},
{
Subject: "same thread 3 replies",
Comment: `<a href="#p92834152" class="quotelink">&gt;&gt;92834152</a><br>paying for free software?<br><br><a href="#p92835905" class="quotelink">&gt;&gt;92835905</a><br>based<br><br><a href="#p92838617" class="quotelink">&gt;&gt;92838617</a><br>paying for free software?<br><br>`,
Id: 92838617,
Time: time.Now(),
},
},
}

func TestOp(t *testing.T) {
thread := toThread(testThread)
got := thread.op.id
expected := 92834152
if got != expected {
t.Errorf("got %d expected %d", got, expected)
}
}

// func TestExplodePost(t *testing.T) {
// post := Post{
// comment: `<a href="#p92834152" class="quotelink">&gt;&gt;92834152</a><br>Yes https://jetbra.in/s`,
// created: time.Now(),
// }
// posts := explodePost(post)
// fmt.Println(posts)
// }

func TestNParents(t *testing.T) {
thread := toThread(testThread)
got := len(thread.posts)
expected := 6
if got != expected {
t.Errorf("got %d expected %d", got, expected)
}
}

func TestGetParentId(t *testing.T) {
findings := map[string]int{
`<a href="/g/thread/92865685#p92866880" class="quotelink">&gt;&gt;92866880</a> <br>`: 0,
`<a href="#p92834152" class="quotelink">&gt;&gt;92834152</a><br>`: 92834152,
`<a href="#p92834152" class="quotelink">&gt;&gt;92834152</a> <br>`: 92834152,
``: 0,
}
for finding, expected := range findings {
got := getParentId(finding)
if expected != got {
t.Errorf("got %d expected %d", got, expected)
}
}
}
Loading

0 comments on commit 8b23614

Please sign in to comment.