Skip to content

Commit

Permalink
Implement Recommendations
Browse files Browse the repository at this point in the history
  • Loading branch information
jackyzy823 committed Oct 2, 2021
1 parent 5caf774 commit de32dbd
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 10 deletions.
6 changes: 6 additions & 0 deletions src/api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ proc getProfile*(username: string): Future[Profile] {.async.} =
url = userShow ? ps
result = parseUserShow(await fetch(url, oldApi=true), username)

proc getRecommendations*(id: string) : Future[Recommendations] {.async.} =
let
ps = genParams({"user_id": id }) # , "limit": "100" 1) limit here or 2) fetch all and limit in display?
url = recommendations ? ps
result = parseRecommnedations(await fetch(url, oldApi = true))

proc getTimeline*(id: string; after=""; replies=false): Future[Timeline] {.async.} =
let
ps = genParams({"userId": id, "include_tweet_replies": $replies}, after)
Expand Down
1 change: 1 addition & 0 deletions src/consts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const
userShow* = api / "1.1/users/show.json"
photoRail* = api / "1.1/statuses/media_timeline.json"
search* = api / "2/search/adaptive.json"
recommendations* = api / "1.1/users/recommendations.json"

timelineApi = api / "2/timeline"
tweet* = timelineApi / "conversation"
Expand Down
4 changes: 4 additions & 0 deletions src/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ proc parseUserShow*(js: JsonNode; username: string): Profile =

result = parseProfile(js)

proc parseRecommnedations*(js: JsonNode) : Recommendations =
for u in js:
result.add parseProfile(u{"user"})

proc parseGraphProfile*(js: JsonNode; username: string): Profile =
if js.isNull: return
with error, js{"errors"}:
Expand Down
12 changes: 12 additions & 0 deletions src/redis_cache.nim
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ proc cache*(data: List) {.async.} =
proc cache*(data: PhotoRail; name: string) {.async.} =
await setex("pr:" & name, baseCacheTime, compress(freeze(data)))

proc cache*(data: Recommendations; user_id: string) {.async.} =
await setex("rc:" & user_id , listCacheTime , compress(freeze(data)))

proc cache*(data: Profile) {.async.} =
if data.username.len == 0 or data.id.len == 0: return
let name = toLower(data.username)
Expand Down Expand Up @@ -109,6 +112,15 @@ proc getCachedPhotoRail*(name: string): Future[PhotoRail] {.async.} =
result = await getPhotoRail(name)
await cache(result, name)

proc getCachedRecommendations*(user_id: string ): Future[Recommendations] {.async.} =
if user_id.len == 0: return
let recommendations = await get("rc:" & user_id )
if recommendations != redisNil:
uncompress(recommendations).thaw(result)
else:
result = await getRecommendations(user_id)
await cache(result,user_id)

proc getCachedList*(username=""; name=""; id=""): Future[List] {.async.} =
let list = if id.len > 0: redisNil
else: await get(toLower("l:" & username & '/' & name))
Expand Down
2 changes: 1 addition & 1 deletion src/routes/rss.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ proc timelineRss*(req: Request; cfg: Config; query: Query): Future[Rss] {.async.

if names.len == 1:
(profile, timeline) =
await fetchSingleTimeline(after, query, skipRail=true)
await fetchSingleTimeline(after, query, skipRail=true, skipRecommendations=true)
else:
var q = query
q.fromUser = names
Expand Down
19 changes: 13 additions & 6 deletions src/routes/timeline.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ proc getQuery*(request: Request; tab, name: string): Query =
of "search": initQuery(params(request), name=name)
else: Query(fromUser: @[name])

proc fetchSingleTimeline*(after: string; query: Query; skipRail=false):
Future[(Profile, Timeline, PhotoRail)] {.async.} =
proc fetchSingleTimeline*(after: string; query: Query; skipRail=false , skipRecommendations=false):
Future[(Profile, Timeline, PhotoRail, Recommendations)] {.async.} =
let name = query.fromUser[0]

var
Expand Down Expand Up @@ -51,6 +51,13 @@ proc fetchSingleTimeline*(after: string; query: Query; skipRail=false):
else:
rail = getCachedPhotoRail(name)

var recommendations: Future[Recommendations]
if skipRecommendations:
recommendations = newFuture[Recommendations]()
recommendations.complete(@[])
else:
recommendations= getCachedRecommendations(profileId)

var timeline =
case query.kind
of posts: await getTimeline(profileId, after)
Expand All @@ -75,7 +82,7 @@ proc fetchSingleTimeline*(after: string; query: Query; skipRail=false):
if fetched and not found:
await cache(profile)

return (profile, timeline, await rail)
return (profile, timeline, await rail ,await recommendations)

proc get*(req: Request; key: string): string =
params(req).getOrDefault(key)
Expand All @@ -88,12 +95,12 @@ proc showTimeline*(request: Request; query: Query; cfg: Config; prefs: Prefs;
html = renderTweetSearch(timeline, prefs, getPath())
return renderMain(html, request, cfg, prefs, "Multi", rss=rss)

var (p, t, r) = await fetchSingleTimeline(after, query)
var (p, t, r ,rc) = await fetchSingleTimeline(after, query)

if p.suspended: return showError(getSuspended(p.username), cfg)
if p.id.len == 0: return

let pHtml = renderProfile(p, t, r, prefs, getPath())
let pHtml = renderProfile(p, t, r, rc, prefs, getPath())
result = renderMain(pHtml, request, cfg, prefs, pageTitle(p), pageDesc(p),
rss=rss, images = @[p.getUserpic("_400x400")],
banner=p.banner)
Expand Down Expand Up @@ -126,7 +133,7 @@ proc createTimelineRouter*(cfg: Config) =
timeline.beginning = true
resp $renderTweetSearch(timeline, prefs, getPath())
else:
var (_, timeline, _) = await fetchSingleTimeline(after, query, skipRail=true)
var (_, timeline, _ , _ ) = await fetchSingleTimeline(after, query, skipRail=true , skipRecommendations = true)
if timeline.content.len == 0: resp Http404
timeline.beginning = true
resp $renderTimelineTweets(timeline, prefs, getPath())
Expand Down
1 change: 1 addition & 0 deletions src/sass/profile/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

@import 'card';
@import 'photo-rail';
@import 'recommendations';

.profile-tabs {
@include panel(auto, 900px);
Expand Down
59 changes: 59 additions & 0 deletions src/sass/profile/recommendations.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@import '_variables';

.recommendations {
&-card {
float: left;
background: var(--bg_panel);
border-radius: 0 0 4px 4px;
width: 100%;
margin: 5px 0;
}

&-header {
padding: 5px 12px 0;
}

&-header-mobile {
display: none;
box-sizing: border-box;
padding: 5px 12px 0;
width: 100%;
float: unset;
color: var(--accent);
justify-content: space-between;
}
}

@include create-toggle(recommendations-list, 640px);
#recommendations-list-toggle:checked ~ .recommendations-list {
padding-bottom: 12px;
}

@media(max-width: 600px) {
.recommendations-header {
display: none;
}

.recommendations-header-mobile {
display: flex;
}

.recommendations-list {
max-height: 0;
padding-bottom: 0;
overflow: scroll;
transition: max-height 0.4s;
}
}

@media(max-width: 600px) {
#recommendations-list-toggle:checked ~ .recommendations-list {
max-height: 160px;
}
}

@media(max-width: 450px) {
#recommendations-list-toggle:checked ~ .recommendations-list {
max-height: 160px;
}
}
2 changes: 2 additions & 0 deletions src/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ type

PhotoRail* = seq[GalleryPhoto]

Recommendations* = seq[Profile]

Poll* = object
options*: seq[string]
values*: seq[int]
Expand Down
22 changes: 20 additions & 2 deletions src/views/profile.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import strutils, strformat
import karax/[karaxdsl, vdom, vstyles]

import renderutils, search
import renderutils, search, timeline
import ".."/[types, utils, formatters]

proc renderStat(num, class: string; text=""): VNode =
Expand Down Expand Up @@ -80,6 +80,20 @@ proc renderPhotoRail(profile: Profile; photoRail: PhotoRail): VNode =
style={backgroundColor: col}):
genImg(photo.url & (if "format" in photo.url: "" else: ":thumb"))

proc renderRecommendations(recommendations: Recommendations, prefs: Prefs): VNode =
buildHtml(tdiv(class="recommendations-card")):
tdiv(class="recommendations-header"):
span: text "You might like"

input(id="recommendations-list-toggle", `type`="checkbox")
label(`for`="recommendations-list-toggle", class="recommendations-header-mobile"):
span: text "You might like"
icon "down"

tdiv(class="recommendations-list"):
for i , recommendation in recommendations:
renderUser(recommendation, prefs)

proc renderBanner(profile: Profile): VNode =
buildHtml():
if "#" in profile.banner:
Expand All @@ -95,7 +109,7 @@ proc renderProtected(username: string): VNode =
p: text &"Only confirmed followers have access to @{username}'s tweets."

proc renderProfile*(profile: Profile; timeline: var Timeline;
photoRail: PhotoRail; prefs: Prefs; path: string): VNode =
photoRail: PhotoRail; recommendations: Recommendations; prefs: Prefs; path: string): VNode =
timeline.query.fromUser = @[profile.username]
buildHtml(tdiv(class="profile-tabs")):
if not prefs.hideBanner:
Expand All @@ -107,6 +121,10 @@ proc renderProfile*(profile: Profile; timeline: var Timeline;
renderProfileCard(profile, prefs)
if photoRail.len > 0:
renderPhotoRail(profile, photoRail)
if recommendations.len > 0:
renderRecommendations(recommendations, prefs)



if profile.protected:
renderProtected(profile.username)
Expand Down
2 changes: 1 addition & 1 deletion src/views/timeline.nim
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ proc threadFilter(tweets: openArray[Tweet]; threads: openArray[int64]; it: Tweet
elif t.replyId == result[0].id:
result.add t

proc renderUser(user: Profile; prefs: Prefs): VNode =
proc renderUser*(user: Profile; prefs: Prefs): VNode =
buildHtml(tdiv(class="timeline-item")):
a(class="tweet-link", href=("/" & user.username))
tdiv(class="tweet-body profile-result"):
Expand Down

0 comments on commit de32dbd

Please sign in to comment.