timeline.nim 2.3 KB

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