diff --git a/doc/TODO.txt b/doc/TODO.txt index 8fc051c..7609a4b 100644 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -79,7 +79,6 @@ TODO: mobile-requests - implement mobile versions of various requests - Check in `pkg/scraper/test_responses/mobile_requests` - TODO: search-bottom-cursor - Entry type "TimelineReplaceEntries" that replaces the cursor in the timeline instead of the new timeline having a new one - As first step, need helper function that returns the []Instruction element in a APIV2Response (not just the MainInstruction which is TimelineAddEntries) @@ -103,7 +102,6 @@ TODO: login-routes-tests TODO: web-ui-downloading - web UI needs buttons to trigger a scrape / refresh manually - - user feed - timeline TODO: webserver-session-arg-active-user @@ -121,5 +119,8 @@ TODO: image-width-and-height - Images should have explicit "width" and "height" attributes. This reduces Cumulative Layout Shift (CLS) while loading the page. - https://web.dev/optimize-cls/#images-without-dimensions -TODO: quote-tweet-icon -- show quote-tweets on a tweet +TODO: download-buttons-not-ugly +- Make the options buttons for downloading less ugly (rn they are ugly) + +TODO: show-errors-in-UI +- if an HTTP request fails, show an error in the UI somehow diff --git a/internal/webserver/handler_user_feed.go b/internal/webserver/handler_user_feed.go index 185896f..1069d4d 100644 --- a/internal/webserver/handler_user_feed.go +++ b/internal/webserver/handler_user_feed.go @@ -34,9 +34,6 @@ func (app *Application) UserFeed(w http.ResponseWriter, r *http.Request) { app.traceLog.Printf("'UserFeed' handler (path: %q)", r.URL.Path) parts := strings.Split(strings.Trim(r.URL.Path, "/"), "/") - if len(parts) != 1 { - app.error_404(w) - } user, err := app.Profile.GetUserByHandle(scraper.UserHandle(parts[0])) if err != nil { @@ -44,6 +41,21 @@ func (app *Application) UserFeed(w http.ResponseWriter, r *http.Request) { return } + if len(parts) == 2 && parts[1] == "scrape" { + if app.IsScrapingDisabled { + http.Error(w, "Scraping is disabled (are you logged in?)", 401) + return + } + + // Run scraper + trove, err := scraper.GetUserFeedGraphqlFor(user.ID, 50) // TODO: parameterizable + if err != nil { + app.ErrorLog.Print(err) + // TOOD: show error in UI + } + app.Profile.SaveTweetTrove(trove) + } + c := persistence.NewUserFeedCursor(user.Handle) err = parse_cursor_value(&c, r) if err != nil { diff --git a/internal/webserver/static/icons/quote.svg b/internal/webserver/static/icons/quote.svg new file mode 100644 index 0000000..4e4eaf3 --- /dev/null +++ b/internal/webserver/static/icons/quote.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/internal/webserver/static/styles.css b/internal/webserver/static/styles.css index 5c074d8..e277106 100644 --- a/internal/webserver/static/styles.css +++ b/internal/webserver/static/styles.css @@ -546,6 +546,7 @@ ul.dropdown-items { position: absolute; top: 2em; width: fit-content; + margin: 0; padding: 0.3em; background-color: var(--color-twitter-off-white); outline: 1px solid var(--color-outline-gray); diff --git a/internal/webserver/tpl/tweet_page_includes/single_tweet.tpl b/internal/webserver/tpl/tweet_page_includes/single_tweet.tpl index fa712ef..8957c08 100644 --- a/internal/webserver/tpl/tweet_page_includes/single_tweet.tpl +++ b/internal/webserver/tpl/tweet_page_includes/single_tweet.tpl @@ -91,10 +91,10 @@
- +
{{$main_tweet.NumReplies}} diff --git a/internal/webserver/tpl/user_feed.tpl b/internal/webserver/tpl/user_feed.tpl index 6466c8b..7dbb929 100644 --- a/internal/webserver/tpl/user_feed.tpl +++ b/internal/webserver/tpl/user_feed.tpl @@ -41,6 +41,26 @@ is following {{$user.FollowingCount}}
+ + diff --git a/pkg/scraper/api_request_utils.go b/pkg/scraper/api_request_utils.go index b4ad108..f29e1ba 100644 --- a/pkg/scraper/api_request_utils.go +++ b/pkg/scraper/api_request_utils.go @@ -287,6 +287,11 @@ func (api *API) do_http(url string, cursor string, result interface{}) error { } defer resp.Body.Close() + if api.IsAuthenticated { + // New request has been made, so the cookie will be changed; update the csrf to match + api.update_csrf_token() + } + if resp.StatusCode != 200 && resp.StatusCode != 403 { content, err := io.ReadAll(resp.Body) if err != nil { @@ -311,10 +316,6 @@ func (api *API) do_http(url string, cursor string, result interface{}) error { return fmt.Errorf("Error parsing API response:\n %w", err) } - if api.IsAuthenticated { - // New request has been made, so the cookie will be changed; update the csrf to match - api.update_csrf_token() - } return nil }