timeline.nim 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import asyncdispatch, strutils, sequtils, uri
  2. import jester
  3. import router_utils
  4. import ".."/[api, types, cache, formatters, agents, query]
  5. import ../views/[general, profile, timeline, status, search]
  6. export uri, sequtils
  7. export router_utils
  8. export api, cache, formatters, query, agents
  9. export profile, timeline, status
  10. type ProfileTimeline = (Profile, Timeline, seq[GalleryPhoto])
  11. proc fetchSingleTimeline*(name, after, agent: string;
  12. query: Query): Future[ProfileTimeline] {.async.} =
  13. let railFut = getPhotoRail(name, agent)
  14. var timeline: Timeline
  15. var profile: Profile
  16. var cachedProfile = hasCachedProfile(name)
  17. if cachedProfile.isSome:
  18. profile = get(cachedProfile)
  19. if query.kind == posts:
  20. if cachedProfile.isSome:
  21. timeline = await getTimeline(name, after, agent)
  22. else:
  23. (profile, timeline) = await getProfileAndTimeline(name, agent, after)
  24. cache(profile)
  25. else:
  26. var timelineFut = getSearch[Tweet](query, after, agent)
  27. if cachedProfile.isNone:
  28. profile = await getCachedProfile(name, agent)
  29. timeline = await timelineFut
  30. if profile.username.len == 0: return
  31. return (profile, timeline, await railFut)
  32. proc fetchMultiTimeline*(names: seq[string]; after, agent: string;
  33. query: Query): Future[Timeline] {.async.} =
  34. var q = query
  35. q.fromUser = names
  36. if q.kind == posts and "replies" notin q.excludes:
  37. q.excludes.add "replies"
  38. return await getSearch[Tweet](q, after, agent)
  39. proc get*(req: Request; key: string): string =
  40. if key in params(req): params(req)[key]
  41. else: ""
  42. proc showTimeline*(request: Request; query: Query; title, rss: string): Future[string] {.async.} =
  43. let
  44. agent = getAgent()
  45. prefs = cookiePrefs()
  46. name = request.get("name")
  47. after = request.get("after")
  48. names = name.strip(chars={'/'}).split(",").filterIt(it.len > 0)
  49. if names.len == 1:
  50. let (p, t, r) = await fetchSingleTimeline(names[0], after, agent, query)
  51. if p.username.len == 0: return
  52. let pHtml = renderProfile(p, t, r, prefs, getPath())
  53. return renderMain(pHtml, request, title, pageTitle(p), pageDesc(p), rss=rss)
  54. else:
  55. let
  56. timeline = await fetchMultiTimeline(names, after, agent, query)
  57. html = renderTweetSearch(timeline, prefs, getPath())
  58. return renderMain(html, request, title, "Multi")
  59. template respTimeline*(timeline: typed) =
  60. if timeline.len == 0:
  61. resp Http404, showError("User \"" & @"name" & "\" not found", cfg.title)
  62. resp timeline
  63. proc createTimelineRouter*(cfg: Config) =
  64. setProfileCacheTime(cfg.profileCacheTime)
  65. router timeline:
  66. get "/@name/?":
  67. cond '.' notin @"name"
  68. let rss = "/$1/rss" % @"name"
  69. respTimeline(await showTimeline(request, Query(), cfg.title, rss))
  70. get "/@name/replies":
  71. cond '.' notin @"name"
  72. let rss = "/$1/replies/rss" % @"name"
  73. respTimeline(await showTimeline(request, getReplyQuery(@"name"), cfg.title, rss))
  74. get "/@name/media":
  75. cond '.' notin @"name"
  76. let rss = "/$1/media/rss" % @"name"
  77. respTimeline(await showTimeline(request, getMediaQuery(@"name"), cfg.title, rss))
  78. get "/@name/search":
  79. cond '.' notin @"name"
  80. let query = initQuery(params(request), name=(@"name"))
  81. let rss = "/$1/search/rss?$2" % [@"name", genQueryUrl(query)]
  82. respTimeline(await showTimeline(request, query, cfg.title, rss))