timeline.nim 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import httpclient, asyncdispatch, htmlparser, strformat
  2. import sequtils, strutils, json, xmltree, uri
  3. import ".."/[types, parser, parserutils, formatters, query]
  4. import utils, consts, media, search
  5. proc finishTimeline*(json: JsonNode; query: Query; after, agent: string): Future[Timeline] {.async.} =
  6. result = getResult[Tweet](json, query, after)
  7. if json == nil: return
  8. if json["new_latent_count"].to(int) == 0: return
  9. if not json.hasKey("items_html"): return
  10. let
  11. html = parseHtml(json["items_html"].to(string))
  12. thread = parseThread(html)
  13. vidsFut = getVideos(thread, agent)
  14. pollFut = getPolls(thread, agent)
  15. cardFut = getCards(thread, agent)
  16. await all(vidsFut, pollFut, cardFut)
  17. result.content = thread.content
  18. proc getTimeline*(username, after, agent: string): Future[Timeline] {.async.} =
  19. let headers = newHttpHeaders({
  20. "Accept": jsonAccept,
  21. "Referer": $(base / username),
  22. "User-Agent": agent,
  23. "X-Twitter-Active-User": "yes",
  24. "X-Requested-With": "XMLHttpRequest",
  25. "Accept-Language": lang
  26. })
  27. var params = toSeq({
  28. "include_available_features": "1",
  29. "include_entities": "1",
  30. "include_new_items_bar": "false",
  31. "reset_error_state": "false"
  32. })
  33. if after.len > 0:
  34. params.add {"max_position": after}
  35. let json = await fetchJson(base / (timelineUrl % username) ? params, headers)
  36. result = await finishTimeline(json, Query(), after, agent)
  37. proc getProfileAndTimeline*(username, agent, after: string): Future[(Profile, Timeline)] {.async.} =
  38. let headers = newHttpHeaders({
  39. "authority": "twitter.com",
  40. "accept": htmlAccept,
  41. "referer": "https://twitter.com/" & username,
  42. "accept-language": lang
  43. })
  44. var url = base / username
  45. if after.len > 0:
  46. url = url ? {"max_position": after}
  47. let
  48. html = await fetchHtml(url, headers)
  49. timeline = parseTimeline(html.select("#timeline > .stream-container"), after)
  50. profile = parseTimelineProfile(html)
  51. vidsFut = getVideos(timeline, agent)
  52. pollFut = getPolls(timeline, agent)
  53. cardFut = getCards(timeline, agent)
  54. await all(vidsFut, pollFut, cardFut)
  55. result = (profile, timeline)