diff --git a/.dockerignore b/.dockerignore index bbfd30f..88cef9a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,4 @@ * +!Gopkg.* !*.go !server/* diff --git a/.gitignore b/.gitignore index 3990fde..f744723 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.db gggtracker +/vendor diff --git a/Dockerfile b/Dockerfile index f94d04f..3c7f0b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,12 @@ -FROM golang:alpine +FROM golang:1.10-alpine WORKDIR /go/src/github.com/ccbrown/gggtracker -ADD . . -RUN apk add --no-cache git && go get -t ./... +RUN apk add --no-cache git +RUN wget -O - https://raw.githubusercontent.com/golang/dep/master/install.sh | sh + +ADD . . +RUN dep ensure RUN go vet . && go test -v ./... RUN go build . diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..2c713f1 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,224 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/PuerkitoBio/goquery" + packages = ["."] + revision = "09540e565986583836b5fc792fe951ec5fd201dd" + version = "v1.3.0" + +[[projects]] + name = "github.com/andybalholm/cascadia" + packages = ["."] + revision = "901648c87902174f774fac311d7f176f8647bdaa" + version = "v1.0.0" + +[[projects]] + name = "github.com/boltdb/bolt" + packages = ["."] + revision = "2f1ce7a837dcb8da3ec595b1dac9d0632f0f99e8" + version = "v1.3.1" + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "346938d642f2ec3594ed81d874461961cd0faa76" + version = "v1.1.0" + +[[projects]] + name = "github.com/dgrijalva/jwt-go" + packages = ["."] + revision = "dbeaa9332f19a944acb5736b4456cfcc02140e29" + version = "v3.1.0" + +[[projects]] + name = "github.com/fsnotify/fsnotify" + packages = ["."] + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token" + ] + revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" + +[[projects]] + name = "github.com/labstack/echo" + packages = [ + ".", + "middleware" + ] + revision = "b338075a0fc6e1a0683dbf03d09b4957a289e26f" + version = "3.2.6" + +[[projects]] + name = "github.com/labstack/gommon" + packages = [ + "bytes", + "color", + "log", + "random" + ] + revision = "57409ada9da0f2afad6664c49502f8c50fbd8476" + version = "0.2.3" + +[[projects]] + name = "github.com/magiconair/properties" + packages = ["."] + revision = "c3beff4c2358b44d0493c7dda585e7db7ff28ae6" + version = "v1.7.6" + +[[projects]] + name = "github.com/mattn/go-colorable" + packages = ["."] + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + +[[projects]] + name = "github.com/mattn/go-isatty" + packages = ["."] + revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" + version = "v0.0.3" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + revision = "00c29f56e2386353d58c599509e8dc3801b0d716" + +[[projects]] + name = "github.com/pelletier/go-toml" + packages = ["."] + revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8" + version = "v1.1.0" + +[[projects]] + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + name = "github.com/sirupsen/logrus" + packages = ["."] + revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba" + version = "v1.0.4" + +[[projects]] + name = "github.com/spf13/afero" + packages = [ + ".", + "mem" + ] + revision = "bb8f1927f2a9d3ab41c9340aa034f6b803f4359c" + version = "v1.0.2" + +[[projects]] + name = "github.com/spf13/cast" + packages = ["."] + revision = "8965335b8c7107321228e3e3702cab9832751bac" + version = "v1.2.0" + +[[projects]] + branch = "master" + name = "github.com/spf13/jwalterweatherman" + packages = ["."] + revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394" + +[[projects]] + name = "github.com/spf13/pflag" + packages = ["."] + revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66" + version = "v1.0.0" + +[[projects]] + name = "github.com/spf13/viper" + packages = ["."] + revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7" + version = "v1.0.0" + +[[projects]] + name = "github.com/stretchr/testify" + packages = [ + "assert", + "require" + ] + revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" + version = "v1.2.1" + +[[projects]] + branch = "master" + name = "github.com/valyala/bytebufferpool" + packages = ["."] + revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7" + +[[projects]] + branch = "master" + name = "github.com/valyala/fasttemplate" + packages = ["."] + revision = "dcecefd839c4193db0d35b88ec65b4c12d360ab0" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = [ + "acme", + "acme/autocert", + "ssh/terminal" + ] + revision = "91a49db82a88618983a78a06c1cbd4e00ab749ab" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = [ + "html", + "html/atom" + ] + revision = "22ae77b79946ea320088417e4d50825671d82d57" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows" + ] + revision = "dd2ff4accc098aceecb86b36eaa7829b2a17b1c9" + +[[projects]] + name = "golang.org/x/text" + packages = [ + "internal/gen", + "internal/triegen", + "internal/ucd", + "transform", + "unicode/cldr", + "unicode/norm" + ] + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5" + version = "v2.1.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "fb3f71f8b31a4ef69f8c12df7c17800632ad541fb57db8b99989ec33570b63fd" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..e04d3c1 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,58 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/PuerkitoBio/goquery" + version = "1.3.0" + +[[constraint]] + name = "github.com/boltdb/bolt" + version = "1.3.1" + +[[constraint]] + name = "github.com/labstack/echo" + version = "3.2.6" + +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.0.4" + +[[constraint]] + name = "github.com/spf13/pflag" + version = "1.0.0" + +[[constraint]] + name = "github.com/spf13/viper" + version = "1.0.0" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.2.1" + +[prune] + go-tests = true + unused-packages = true diff --git a/main.go b/main.go index 7af8c20..56cd657 100644 --- a/main.go +++ b/main.go @@ -5,9 +5,9 @@ import ( "net/http" "path" - log "github.com/Sirupsen/logrus" "github.com/labstack/echo" "github.com/labstack/echo/middleware" + log "github.com/sirupsen/logrus" "github.com/spf13/pflag" "github.com/spf13/viper" diff --git a/server/activity.go b/server/activity.go index 0c8fbe4..427020b 100644 --- a/server/activity.go +++ b/server/activity.go @@ -1,6 +1,8 @@ package server import ( + "net/http" + "strings" "time" ) @@ -8,3 +10,43 @@ type Activity interface { ActivityTime() time.Time ActivityKey() uint32 } + +func ActivityFilterForRequest(r *http.Request) func(Activity) bool { + subdomain := "" + if r.Host != "" { + subdomain = strings.Split(r.Host, ".")[0] + } + + includeReddit := false + includeForumHost := map[string]bool{} + + switch subdomain { + case "br": + includeForumHost["br.pathofexile.com"] = true + case "ru": + includeForumHost["ru.pathofexile.com"] = true + case "th": + includeForumHost["th.pathofexile.com"] = true + case "de": + includeForumHost["de.pathofexile.com"] = true + case "fr": + includeForumHost["fr.pathofexile.com"] = true + case "es": + includeForumHost["es.pathofexile.com"] = true + default: + includeReddit = true + includeForumHost["www.pathofexile.com"] = true + } + + return func(a Activity) bool { + switch a := a.(type) { + case *ForumPost: + return includeForumHost[a.Host] + case *RedditComment: + return includeReddit + case *RedditPost: + return includeReddit + } + return false + } +} diff --git a/server/activity_handler.go b/server/activity_handler.go index 6530cc1..f75ebb9 100644 --- a/server/activity_handler.go +++ b/server/activity_handler.go @@ -16,7 +16,7 @@ type jsonResponse struct { func ActivityHandler(db *Database) echo.HandlerFunc { return func(c echo.Context) error { - activity, next := db.Activity(c.QueryParam("next"), 50) + activity, next := db.Activity(c.QueryParam("next"), 50, ActivityFilterForRequest(c.Request())) response := jsonResponse{ Next: next, } diff --git a/server/database.go b/server/database.go index 00a4891..a79679b 100644 --- a/server/database.go +++ b/server/database.go @@ -69,7 +69,7 @@ func (db *Database) AddActivity(activity []Activity) { } } -func (db *Database) Activity(start string, count int) ([]Activity, string) { +func (db *Database) Activity(start string, count int, filter func(Activity) bool) ([]Activity, string) { ret := []Activity(nil) next := "" err := db.db.View(func(tx *bolt.Tx) error { @@ -88,7 +88,8 @@ func (db *Database) Activity(start string, count int) ([]Activity, string) { } } } - for i := 0; i < count && k != nil; i++ { + for len(ret) < count && k != nil { + var activity Activity switch k[5] { case ForumPostType: post := &ForumPost{} @@ -96,23 +97,29 @@ func (db *Database) Activity(start string, count int) ([]Activity, string) { if err != nil { return err } - ret = append(ret, post) + if post.Host == "" { + post.Host = "www.pathofexile.com" + } + activity = post case RedditCommentType: comment := &RedditComment{} err := json.Unmarshal(v, comment) if err != nil { return err } - ret = append(ret, comment) + activity = comment case RedditPostType: post := &RedditPost{} err := json.Unmarshal(v, post) if err != nil { return err } - ret = append(ret, post) + activity = post + } + if filter == nil || filter(activity) { + ret = append(ret, activity) + next = base64.RawURLEncoding.EncodeToString(k) } - next = base64.RawURLEncoding.EncodeToString(k) k, v = c.Prev() } return nil diff --git a/server/database_test.go b/server/database_test.go index 55e7847..96153b6 100644 --- a/server/database_test.go +++ b/server/database_test.go @@ -34,18 +34,18 @@ func TestDatabase_ForumPosts(t *testing.T) { db.AddActivity([]Activity{post1, post2}) - posts, next := db.Activity("", 1) + posts, next := db.Activity("", 1, nil) require.Equal(t, 1, len(posts)) assert.Equal(t, post1.Id, posts[0].(*ForumPost).Id) assert.Equal(t, post1.Poster, posts[0].(*ForumPost).Poster) assert.Equal(t, post1.Time.Unix(), posts[0].(*ForumPost).Time.Unix()) - posts, next = db.Activity(next, 1) + posts, next = db.Activity(next, 1, nil) require.Equal(t, 1, len(posts)) assert.Equal(t, post2.Id, posts[0].(*ForumPost).Id) assert.Equal(t, post2.Poster, posts[0].(*ForumPost).Poster) assert.Equal(t, post2.Time.Unix(), posts[0].(*ForumPost).Time.Unix()) - posts, _ = db.Activity(next, 1) + posts, _ = db.Activity(next, 1, nil) require.Equal(t, 0, len(posts)) } diff --git a/server/forum_indexer.go b/server/forum_indexer.go index 1405c6a..de4c4bc 100644 --- a/server/forum_indexer.go +++ b/server/forum_indexer.go @@ -9,16 +9,17 @@ import ( "regexp" "strconv" "strings" + "sync" "time" "github.com/PuerkitoBio/goquery" - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" ) type ForumIndexer struct { configuration ForumIndexerConfiguration - closeSignal chan bool + closeSignal chan struct{} } type ForumIndexerConfiguration struct { @@ -29,20 +30,30 @@ type ForumIndexerConfiguration struct { func NewForumIndexer(configuration ForumIndexerConfiguration) (*ForumIndexer, error) { ret := &ForumIndexer{ configuration: configuration, - closeSignal: make(chan bool), + closeSignal: make(chan struct{}), } go ret.run() return ret, nil } func (indexer *ForumIndexer) Close() { - indexer.closeSignal <- true + close(indexer.closeSignal) } func (indexer *ForumIndexer) run() { log.Info("starting forum indexer") - posters := []string{ + hosts := []string{ + "www.pathofexile.com", + "br.pathofexile.com", + "ru.pathofexile.com", + "th.pathofexile.com", + "de.pathofexile.com", + "fr.pathofexile.com", + "es.pathofexile.com", + } + + accounts := []string{ "Chris", "Jonathan", "Erik", "Mark_GGG", "Samantha", "Rory", "Rhys", "Qarl", "Andrew_GGG", "Damien_GGG", "Joel_GGG", "Ari", "Thomas", "BrianWeissman", "Edwin_GGG", "Support", "Dylan", "MaxS", "Ammon_GGG", "Jess_GGG", "Robbie_GGG", "GGG_Neon", "Jason_GGG", "Henry_GGG", @@ -53,39 +64,48 @@ func (indexer *ForumIndexer) run() { "Rachel_GGG", "Rob_GGG", "Roman_GGG", "Sarah_GGG", "SarahB_GGG", "Tom_GGG", "Natalia_GGG", "Jeff_GGG", } - next := 0 timezone := (*time.Location)(nil) - for { + for timezone == nil { select { case <-indexer.closeSignal: return default: - if timezone == nil { - tz, err := indexer.sessionTimezone() - if err != nil { - log.WithError(err).Error("error getting forum timezone") - } else { - timezone = tz - log.WithFields(log.Fields{ - "timezone": timezone, - }).Info("forum timezone obtained") - } + if tz, err := indexer.sessionTimezone(); err != nil { + log.WithError(err).Error("error getting forum timezone") } else { - indexer.index(posters[next], timezone) - next += 1 - if next >= len(posters) { - next = 0 - } + timezone = tz + log.WithField("timezone", timezone).Info("forum timezone obtained") + break } time.Sleep(time.Second) } } + + var wg sync.WaitGroup + wg.Add(len(hosts)) + + for _, host := range hosts { + host := host + go func() { + for _, account := range accounts { + select { + case <-indexer.closeSignal: + return + default: + indexer.index(host, account, timezone) + time.Sleep(time.Second) + } + } + }() + } + + wg.Wait() } -func (indexer *ForumIndexer) requestDocument(resource string) (*goquery.Document, error) { - urlString := fmt.Sprintf("https://www.pathofexile.com/%v", strings.TrimPrefix(resource, "/")) +func (indexer *ForumIndexer) requestDocument(host, resource string) (*goquery.Document, error) { + urlString := fmt.Sprintf("https://%v/%v", host, strings.TrimPrefix(resource, "/")) jar, _ := cookiejar.New(nil) u, _ := url.Parse(urlString) jar.SetCookies(u, []*http.Cookie{ @@ -113,6 +133,33 @@ var postURLExpression = regexp.MustCompile("^/forum/view-thread/([0-9]+)/page/([ var threadURLExpression = regexp.MustCompile("^/forum/view-thread/([0-9]+)") var forumURLExpression = regexp.MustCompile("^/forum/view-forum/([0-9]+)") +var monthReplacer = strings.NewReplacer( + "ม.ค.", "Jan", + "ก.พ.", "Feb", + "มี.ค.", "Mar", + "เม.ย.", "Apr", + "พ.ค.", "May", + "มิ.ย.", "Jun", + "ก.ค.", "Jul", + "ส.ค.", "Aug", + "ก.ย.", "Sep", + "ต.ค.", "Oct", + "พ.ย.", "Nov", + "ธ.ค.", "Dec", + "janv.", "Jan", + "févr.", "Feb", + "mars", "Mar", + "avril", "Apr", + "mai", "May", + "juin", "Jun", + "juil.", "Jul", + "août", "Aug", + "sept.", "Sep", + "oct.", "Oct", + "nov.", "Nov", + "déc.", "Dec", +) + func ScrapeForumPosts(doc *goquery.Document, timezone *time.Location) ([]*ForumPost, error) { posts := []*ForumPost(nil) @@ -129,12 +176,24 @@ func ScrapeForumPosts(doc *goquery.Document, timezone *time.Location) ([]*ForumP } post.BodyHTML = body - text := sel.Find(".post_date").Text() - t, err := time.ParseInLocation("Jan _2, 2006 3:04:05 PM", text, timezone) - if err != nil { + timeText := monthReplacer.Replace(sel.Find(".post_date").Text()) + + for _, format := range []string{ + "Jan _2, 2006 3:04:05 PM", + "2/1/2006 15:04:05", + "2.1.2006 15:04:05", + "_2 Jan 2006, 15:04:05", + "_2 Jan 2006 15:04:05", + } { + if t, err := time.ParseInLocation(format, timeText, timezone); err == nil { + post.Time = t + break + } + } + if post.Time.IsZero() { + log.WithField("text", timeText).Error("unable to parse time") return false } - post.Time = t sel.Find("a").Each(func(i int, sel *goquery.Selection) { href := sel.AttrOr("href", "") @@ -165,16 +224,24 @@ func ScrapeForumPosts(doc *goquery.Document, timezone *time.Location) ([]*ForumP return posts, nil } -func (indexer *ForumIndexer) forumPosts(poster string, page int, timezone *time.Location) ([]*ForumPost, error) { - doc, err := indexer.requestDocument(fmt.Sprintf("/account/view-posts/%v/page/%v", poster, page)) +func (indexer *ForumIndexer) forumPosts(host, poster string, page int, timezone *time.Location) ([]*ForumPost, error) { + doc, err := indexer.requestDocument(host, fmt.Sprintf("/account/view-posts/%v/page/%v", poster, page)) if err != nil { return nil, err } - return ScrapeForumPosts(doc, timezone) + posts, err := ScrapeForumPosts(doc, timezone) + if err != nil { + return nil, err + } + for _, post := range posts { + post.Host = host + } + return posts, nil } -func (indexer *ForumIndexer) index(poster string, timezone *time.Location) { +func (indexer *ForumIndexer) index(host, poster string, timezone *time.Location) { logger := log.WithFields(log.Fields{ + "host": host, "poster": poster, }) @@ -182,7 +249,7 @@ func (indexer *ForumIndexer) index(poster string, timezone *time.Location) { activity := []Activity(nil) for page := 1; ; page++ { - posts, err := indexer.forumPosts(poster, page, timezone) + posts, err := indexer.forumPosts(host, poster, page, timezone) if err != nil { logger.WithError(err).Error("error requesting forum posts") } @@ -195,9 +262,7 @@ func (indexer *ForumIndexer) index(poster string, timezone *time.Location) { activity = append(activity, post) } - logger.WithFields(log.Fields{ - "count": len(posts), - }).Info("received forum posts") + logger.WithField("count", len(posts)).Info("received forum posts") if done { break @@ -219,7 +284,7 @@ func ScrapeForumTimezone(doc *goquery.Document) (*time.Location, error) { } func (indexer *ForumIndexer) sessionTimezone() (*time.Location, error) { - doc, err := indexer.requestDocument("/my-account/preferences") + doc, err := indexer.requestDocument("www.pathofexile.com", "/my-account/preferences") if err != nil { return nil, err } diff --git a/server/forum_post.go b/server/forum_post.go index 09afa7e..872b521 100644 --- a/server/forum_post.go +++ b/server/forum_post.go @@ -7,6 +7,7 @@ import ( type ForumPost struct { Id int `json:"id"` + Host string `json:"host"` BodyHTML string `json:"body_html"` Time time.Time `json:"time"` Poster string `json:"poster"` @@ -26,5 +27,5 @@ func (p *ForumPost) ActivityKey() uint32 { } func (p *ForumPost) PostURL() string { - return fmt.Sprintf("https://www.pathofexile.com/forum/view-post/%v", p.Id) + return fmt.Sprintf("https://%v/forum/view-post/%v", p.Host, p.Id) } diff --git a/server/index_handler.go b/server/index_handler.go index 8716dc7..e21be6e 100644 --- a/server/index_handler.go +++ b/server/index_handler.go @@ -63,7 +63,7 @@ var index = ` - + ` diff --git a/server/reddit_indexer.go b/server/reddit_indexer.go index eab7688..93f5358 100644 --- a/server/reddit_indexer.go +++ b/server/reddit_indexer.go @@ -8,7 +8,7 @@ import ( "strings" "time" - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" ) type RedditIndexerConfiguration struct { diff --git a/server/rss_handler.go b/server/rss_handler.go index 03540be..62dee5d 100644 --- a/server/rss_handler.go +++ b/server/rss_handler.go @@ -43,7 +43,7 @@ type rssResponse struct { func RSSHandler(db *Database) echo.HandlerFunc { return func(c echo.Context) error { - activity, _ := db.Activity(c.QueryParam("next"), 50) + activity, _ := db.Activity(c.QueryParam("next"), 50, ActivityFilterForRequest(c.Request())) response := rssResponse{ Version: "2.0", Atom: "http://www.w3.org/2005/Atom", diff --git a/server/static/index.js b/server/static/index.js index 734075f..3677f7a 100644 --- a/server/static/index.js +++ b/server/static/index.js @@ -37,7 +37,7 @@ function loadActivity() { if (type == 'forum_post') { $tr.append($('').append($('') - .attr('href', 'https://www.pathofexile.com/forum/view-thread/' + activity.thread_id + '/filter-account-type/staff') + .attr('href', 'https://' + activity.host + '/forum/view-thread/' + activity.thread_id + '/filter-account-type/staff') .append($('')) )); } else if (type == 'reddit_comment') { @@ -54,7 +54,7 @@ function loadActivity() { if (type == 'forum_post') { $tr.append($('').append($('') - .attr('href', 'https://www.pathofexile.com/forum/view-post/' + activity.id) + .attr('href', 'https://' + activity.host + '/forum/view-post/' + activity.id) .text(activity.thread_title) )); } else if (type == "reddit_post") { @@ -71,7 +71,7 @@ function loadActivity() { if (type == 'forum_post') { $tr.append($('').append($('') - .attr('href', 'https://www.pathofexile.com/account/view-profile/' + encodeURIComponent(activity.poster)) + .attr('href', 'https://' + activity.host + '/account/view-profile/' + encodeURIComponent(activity.poster)) .text(activity.poster) )); } else { @@ -85,7 +85,7 @@ function loadActivity() { if (type == 'forum_post') { $tr.append($('').append($('') - .attr('href', 'https://www.pathofexile.com/forum/view-forum/' + encodeURIComponent(activity.forum_id)) + .attr('href', 'https://' + activity.host + '/forum/view-forum/' + encodeURIComponent(activity.forum_id)) .text(activity.forum_name) )); } else { @@ -107,7 +107,7 @@ function loadActivity() { $body.find('a').each(function() { var r = $(this).attr('href'); if (r && (r.indexOf(':') < 0 || r.indexOf('/') <= r.indexOf(':'))) { - var root = type == 'forum_post' ? 'https://www.pathofexile.com' : 'https://www.reddit.com'; + var root = type == 'forum_post' ? 'https://' + activity.host : 'https://www.reddit.com'; $(this).attr('href', root + (r[0] == '/' ? '' : '/') + r); } });