2021-09-08 18:05:39 +00:00
|
|
|
import httpclient
|
|
|
|
import json
|
|
|
|
import strformat
|
|
|
|
import os
|
|
|
|
import sequtils
|
2021-09-20 14:07:22 +00:00
|
|
|
import chronicles
|
2021-09-20 16:21:30 +00:00
|
|
|
import uri
|
2021-09-08 18:05:39 +00:00
|
|
|
|
2021-09-11 21:50:36 +00:00
|
|
|
from statusgo_backend/gif import getRecentGifs, getFavoriteGifs, setFavoriteGifs, setRecentGifs
|
2021-09-08 18:05:39 +00:00
|
|
|
|
2021-09-20 14:07:22 +00:00
|
|
|
logScope:
|
|
|
|
topics = "gif"
|
2021-09-08 18:05:39 +00:00
|
|
|
|
|
|
|
const MAX_RECENT = 50
|
|
|
|
# set via `nim c` param `-d:TENOR_API_KEY:[api_key]`; should be set in CI/release builds
|
|
|
|
const TENOR_API_KEY {.strdefine.} = ""
|
|
|
|
let TENOR_API_KEY_ENV = $getEnv("TENOR_API_KEY")
|
|
|
|
|
|
|
|
let TENOR_API_KEY_RESOLVED =
|
|
|
|
if TENOR_API_KEY_ENV != "":
|
|
|
|
TENOR_API_KEY_ENV
|
|
|
|
else:
|
|
|
|
TENOR_API_KEY
|
|
|
|
|
|
|
|
const baseUrl = "https://g.tenor.com/v1/"
|
|
|
|
let defaultParams = fmt("&media_filter=minimal&limit=50&key={TENOR_API_KEY_RESOLVED}")
|
|
|
|
|
|
|
|
type
|
|
|
|
GifItem* = object
|
|
|
|
id*: string
|
|
|
|
title*: string
|
|
|
|
url*: string
|
|
|
|
tinyUrl*: string
|
|
|
|
height*: int
|
|
|
|
|
|
|
|
proc tenorToGifItem(jsonMsg: JsonNode): GifItem =
|
|
|
|
return GifItem(
|
|
|
|
id: jsonMsg{"id"}.getStr,
|
|
|
|
title: jsonMsg{"title"}.getStr,
|
|
|
|
url: jsonMsg{"media"}[0]["gif"]["url"].getStr,
|
|
|
|
tinyUrl: jsonMsg{"media"}[0]["tinygif"]["url"].getStr,
|
|
|
|
height: jsonMsg{"media"}[0]["gif"]["dims"][1].getInt
|
|
|
|
)
|
|
|
|
|
|
|
|
proc settingToGifItem(jsonMsg: JsonNode): GifItem =
|
|
|
|
return GifItem(
|
|
|
|
id: jsonMsg{"id"}.getStr,
|
|
|
|
title: jsonMsg{"title"}.getStr,
|
|
|
|
url: jsonMsg{"url"}.getStr,
|
|
|
|
tinyUrl: jsonMsg{"tinyUrl"}.getStr,
|
|
|
|
height: jsonMsg{"height"}.getInt
|
|
|
|
)
|
|
|
|
|
|
|
|
proc toJsonNode*(self: GifItem): JsonNode =
|
|
|
|
result = %* {
|
|
|
|
"id": self.id,
|
|
|
|
"title": self.title,
|
|
|
|
"url": self.url,
|
|
|
|
"tinyUrl": self.tinyUrl,
|
|
|
|
"height": self.height
|
|
|
|
}
|
|
|
|
|
|
|
|
proc `$`*(self: GifItem): string =
|
|
|
|
return fmt"GifItem(id:{self.id}, title:{self.title}, url:{self.url}, tinyUrl:{self.tinyUrl}, height:{self.height})"
|
|
|
|
|
|
|
|
type
|
|
|
|
GifClient* = ref object
|
|
|
|
client: HttpClient
|
|
|
|
favorites: seq[GifItem]
|
|
|
|
recents: seq[GifItem]
|
|
|
|
favoritesLoaded: bool
|
|
|
|
recentsLoaded: bool
|
|
|
|
|
|
|
|
proc newGifClient*(): GifClient =
|
|
|
|
result = GifClient()
|
|
|
|
result.client = newHttpClient()
|
|
|
|
result.favorites = @[]
|
|
|
|
result.recents = @[]
|
|
|
|
|
2021-09-20 14:07:22 +00:00
|
|
|
proc getContentWithRetry(self: GifClient, path: string, maxRetry: int = 3): string =
|
|
|
|
var currentRetry = 0
|
|
|
|
while true:
|
|
|
|
try:
|
|
|
|
let content = self.client.getContent(fmt("{baseUrl}{path}{defaultParams}"))
|
|
|
|
return content
|
|
|
|
except Exception as e:
|
|
|
|
currentRetry += 1
|
|
|
|
error "could not query tenor API", msg=e.msg
|
|
|
|
|
|
|
|
if currentRetry >= maxRetry:
|
|
|
|
raise
|
|
|
|
|
|
|
|
sleep(100 * currentRetry)
|
|
|
|
|
|
|
|
proc tenorQuery(self: GifClient, path: string): seq[GifItem] =
|
2021-09-08 18:05:39 +00:00
|
|
|
try:
|
2021-09-20 14:07:22 +00:00
|
|
|
let content = self.getContentWithRetry(path)
|
2021-09-08 18:05:39 +00:00
|
|
|
let doc = content.parseJson()
|
|
|
|
|
|
|
|
var items: seq[GifItem] = @[]
|
|
|
|
for json in doc["results"]:
|
|
|
|
items.add(tenorToGifItem(json))
|
|
|
|
|
|
|
|
return items
|
|
|
|
except:
|
|
|
|
return @[]
|
|
|
|
|
|
|
|
proc search*(self: GifClient, query: string): seq[GifItem] =
|
2021-09-20 16:21:30 +00:00
|
|
|
return self.tenorQuery(fmt("search?q={encodeUrl(query)}"))
|
2021-09-08 18:05:39 +00:00
|
|
|
|
|
|
|
proc getTrendings*(self: GifClient): seq[GifItem] =
|
|
|
|
return self.tenorQuery("trending?")
|
|
|
|
|
|
|
|
proc getFavorites*(self: GifClient): seq[GifItem] =
|
|
|
|
if not self.favoritesLoaded:
|
|
|
|
self.favoritesLoaded = true
|
|
|
|
self.favorites = map(getFavoriteGifs(){"items"}.getElems(), settingToGifItem)
|
|
|
|
|
|
|
|
return self.favorites
|
|
|
|
|
|
|
|
proc getRecents*(self: GifClient): seq[GifItem] =
|
|
|
|
if not self.recentsLoaded:
|
|
|
|
self.recentsLoaded = true
|
|
|
|
self.recents = map(getRecentGifs(){"items"}.getElems(), settingToGifItem)
|
|
|
|
|
|
|
|
return self.recents
|
|
|
|
|
|
|
|
proc isFavorite*(self: GifClient, gifItem: GifItem): bool =
|
|
|
|
for favorite in self.getFavorites():
|
|
|
|
if favorite.id == gifItem.id:
|
|
|
|
return true
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
proc toggleFavorite*(self: GifClient, gifItem: GifItem) =
|
|
|
|
var newFavorites: seq[GifItem] = @[]
|
|
|
|
var found = false
|
|
|
|
|
|
|
|
for favoriteGif in self.getFavorites():
|
|
|
|
if favoriteGif.id == gifItem.id:
|
|
|
|
found = true
|
|
|
|
continue
|
|
|
|
|
|
|
|
newFavorites.add(favoriteGif)
|
|
|
|
|
|
|
|
if not found:
|
|
|
|
newFavorites.add(gifItem)
|
|
|
|
|
|
|
|
self.favorites = newFavorites
|
|
|
|
setFavoriteGifs(%*{"items": map(newFavorites, toJsonNode)})
|
|
|
|
|
|
|
|
proc addToRecents*(self: GifClient, gifItem: GifItem) =
|
|
|
|
let recents = self.getRecents()
|
|
|
|
var newRecents: seq[GifItem] = @[gifItem]
|
|
|
|
var idx = 0
|
|
|
|
|
|
|
|
while idx < MAX_RECENT - 1:
|
|
|
|
if idx >= recents.len:
|
|
|
|
break
|
|
|
|
|
|
|
|
if recents[idx].id == gifItem.id:
|
|
|
|
idx += 1
|
|
|
|
continue
|
|
|
|
|
|
|
|
newRecents.add(recents[idx])
|
|
|
|
idx += 1
|
2021-09-20 14:07:22 +00:00
|
|
|
|
2021-09-08 18:05:39 +00:00
|
|
|
self.recents = newRecents
|
|
|
|
setRecentGifs(%*{"items": map(newRecents, toJsonNode)})
|