Switch to packedjson to try lowering memory usage
This commit is contained in:
parent
2fa76db099
commit
fb591e43b8
|
@ -11,10 +11,8 @@ bin = @["nitter"]
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
requires "nim >= 1.2.0"
|
requires "nim >= 1.2.0"
|
||||||
requires "norm#head"
|
|
||||||
requires "jester#head"
|
requires "jester#head"
|
||||||
requires "regex#2d96bab"
|
requires "regex#2d96bab"
|
||||||
requires "q >= 0.0.7"
|
|
||||||
requires "nimcrypto >= 0.4.11"
|
requires "nimcrypto >= 0.4.11"
|
||||||
requires "karax >= 1.1.2"
|
requires "karax >= 1.1.2"
|
||||||
requires "sass"
|
requires "sass"
|
||||||
|
@ -22,6 +20,7 @@ requires "markdown#head"
|
||||||
requires "https://github.com/zedeus/redis#head"
|
requires "https://github.com/zedeus/redis#head"
|
||||||
requires "redpool#head"
|
requires "redpool#head"
|
||||||
requires "msgpack4nim >= 0.3.1"
|
requires "msgpack4nim >= 0.3.1"
|
||||||
|
requires "packedjson"
|
||||||
|
|
||||||
|
|
||||||
# Tasks
|
# Tasks
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import asyncdispatch, httpclient, uri, strutils, json
|
import asyncdispatch, httpclient, uri, strutils
|
||||||
|
import packedjson
|
||||||
import types, query, formatters, consts, apiutils, parser
|
import types, query, formatters, consts, apiutils, parser
|
||||||
|
|
||||||
proc getGraphProfile*(username: string): Future[Profile] {.async.} =
|
proc getGraphProfile*(username: string): Future[Profile] {.async.} =
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import httpclient, asyncdispatch, options, times, strutils, json, uri
|
import httpclient, asyncdispatch, options, times, strutils, uri
|
||||||
import types, agents, tokens, consts
|
import packedjson
|
||||||
|
import types, agents, tokens, consts, parserutils
|
||||||
|
|
||||||
proc genParams*(pars: openarray[(string, string)] = @[];
|
proc genParams*(pars: openarray[(string, string)] = @[];
|
||||||
cursor=""): seq[(string, string)] =
|
cursor=""): seq[(string, string)] =
|
||||||
|
@ -41,19 +42,20 @@ proc fetch*(url: Uri; retried=false; oldApi=false): Future[JsonNode] {.async.} =
|
||||||
|
|
||||||
if resp.status != $Http200:
|
if resp.status != $Http200:
|
||||||
if "Bad guest token" in body:
|
if "Bad guest token" in body:
|
||||||
return
|
keepToken = false
|
||||||
|
return newJNull()
|
||||||
elif not body.startsWith('{'):
|
elif not body.startsWith('{'):
|
||||||
echo resp.status, " ", body
|
echo resp.status, " ", body
|
||||||
return
|
return newJNull()
|
||||||
|
|
||||||
result = parseJson(body)
|
result = parseJson(body)
|
||||||
|
|
||||||
if result{"errors"} != nil and result.getError == forbidden:
|
if result{"errors"}.notNull and result.getError == forbidden:
|
||||||
keepToken = false
|
keepToken = false
|
||||||
echo "bad token"
|
echo "bad token"
|
||||||
except:
|
except:
|
||||||
echo "error: ", url
|
echo "error: ", url
|
||||||
result = nil
|
result = newJNull()
|
||||||
finally:
|
finally:
|
||||||
if keepToken:
|
if keepToken:
|
||||||
token.release()
|
token.release()
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import json, strutils, options, tables, times, math
|
import strutils, options, tables, times, math
|
||||||
|
import packedjson
|
||||||
import types, parserutils
|
import types, parserutils
|
||||||
|
|
||||||
proc parseProfile(js: JsonNode; id=""): Profile =
|
proc parseProfile(js: JsonNode; id=""): Profile =
|
||||||
if js == nil: return
|
if js.isNull: return
|
||||||
result = Profile(
|
result = Profile(
|
||||||
id: if id.len > 0: id else: js{"id_str"}.getStr,
|
id: if id.len > 0: id else: js{"id_str"}.getStr,
|
||||||
username: js{"screen_name"}.getStr,
|
username: js{"screen_name"}.getStr,
|
||||||
|
@ -24,7 +25,7 @@ proc parseProfile(js: JsonNode; id=""): Profile =
|
||||||
result.expandProfileEntities(js)
|
result.expandProfileEntities(js)
|
||||||
|
|
||||||
proc parseUserShow*(js: JsonNode; username: string): Profile =
|
proc parseUserShow*(js: JsonNode; username: string): Profile =
|
||||||
if js == nil: return
|
if js.isNull: return
|
||||||
with error, js{"errors"}:
|
with error, js{"errors"}:
|
||||||
result = Profile(username: username)
|
result = Profile(username: username)
|
||||||
if error.getError == suspended:
|
if error.getError == suspended:
|
||||||
|
@ -34,7 +35,7 @@ proc parseUserShow*(js: JsonNode; username: string): Profile =
|
||||||
result = parseProfile(js)
|
result = parseProfile(js)
|
||||||
|
|
||||||
proc parseGraphProfile*(js: JsonNode; username: string): Profile =
|
proc parseGraphProfile*(js: JsonNode; username: string): Profile =
|
||||||
if js == nil: return
|
if js.isNull: return
|
||||||
with error, js{"errors"}:
|
with error, js{"errors"}:
|
||||||
result = Profile(username: username)
|
result = Profile(username: username)
|
||||||
if error.getError == suspended:
|
if error.getError == suspended:
|
||||||
|
@ -46,12 +47,12 @@ proc parseGraphProfile*(js: JsonNode; username: string): Profile =
|
||||||
parseProfile(user, id)
|
parseProfile(user, id)
|
||||||
|
|
||||||
proc parseGraphList*(js: JsonNode): List =
|
proc parseGraphList*(js: JsonNode): List =
|
||||||
if js == nil: return
|
if js.isNull: return
|
||||||
|
|
||||||
var list = js{"data", "user_by_screen_name", "list"}
|
var list = js{"data", "user_by_screen_name", "list"}
|
||||||
if list == nil:
|
if list.isNull:
|
||||||
list = js{"data", "list"}
|
list = js{"data", "list"}
|
||||||
if list == nil:
|
if list.isNull:
|
||||||
return
|
return
|
||||||
|
|
||||||
result = List(
|
result = List(
|
||||||
|
@ -70,7 +71,7 @@ proc parseListMembers*(js: JsonNode; cursor: string): Result[Profile] =
|
||||||
query: Query(kind: userList)
|
query: Query(kind: userList)
|
||||||
)
|
)
|
||||||
|
|
||||||
if js == nil: return
|
if js.isNull: return
|
||||||
|
|
||||||
result.top = js{"previous_cursor_str"}.getStr
|
result.top = js{"previous_cursor_str"}.getStr
|
||||||
result.bottom = js{"next_cursor_str"}.getStr
|
result.bottom = js{"next_cursor_str"}.getStr
|
||||||
|
@ -116,7 +117,7 @@ proc parseVideo(js: JsonNode): Video =
|
||||||
|
|
||||||
for v in js{"video_info", "variants"}:
|
for v in js{"video_info", "variants"}:
|
||||||
result.variants.add VideoVariant(
|
result.variants.add VideoVariant(
|
||||||
videoType: v{"content_type"}.to(VideoType),
|
videoType: parseEnum[VideoType](v{"content_type"}.getStr("summary")),
|
||||||
bitrate: v{"bitrate"}.getInt,
|
bitrate: v{"bitrate"}.getInt,
|
||||||
url: v{"url"}.getStr
|
url: v{"url"}.getStr
|
||||||
)
|
)
|
||||||
|
@ -192,14 +193,14 @@ proc parseCard(js: JsonNode; urls: JsonNode): Card =
|
||||||
break
|
break
|
||||||
|
|
||||||
proc parseTweet(js: JsonNode): Tweet =
|
proc parseTweet(js: JsonNode): Tweet =
|
||||||
if js == nil: return
|
if js.isNull: return
|
||||||
result = Tweet(
|
result = Tweet(
|
||||||
id: js{"id_str"}.getId,
|
id: js{"id_str"}.getId,
|
||||||
threadId: js{"conversation_id_str"}.getId,
|
threadId: js{"conversation_id_str"}.getId,
|
||||||
replyId: js{"in_reply_to_status_id_str"}.getId,
|
replyId: js{"in_reply_to_status_id_str"}.getId,
|
||||||
text: js{"full_text"}.getStr,
|
text: js{"full_text"}.getStr,
|
||||||
time: js{"created_at"}.getTime,
|
time: js{"created_at"}.getTime,
|
||||||
hasThread: js{"self_thread"} != nil,
|
hasThread: js{"self_thread"}.notNull,
|
||||||
available: true,
|
available: true,
|
||||||
profile: Profile(id: js{"user_id_str"}.getStr),
|
profile: Profile(id: js{"user_id_str"}.getStr),
|
||||||
stats: TweetStats(
|
stats: TweetStats(
|
||||||
|
@ -354,7 +355,7 @@ proc parseTimeline*(js: JsonNode; after=""): Timeline =
|
||||||
if instructions.len == 0: return
|
if instructions.len == 0: return
|
||||||
|
|
||||||
for i in instructions:
|
for i in instructions:
|
||||||
if result.beginning and i{"pinEntry"} != nil:
|
if result.beginning and i{"pinEntry"}.notNull:
|
||||||
with pin, parsePin(i, global):
|
with pin, parsePin(i, global):
|
||||||
result.content.add pin
|
result.content.add pin
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import json, strutils, times, macros, htmlgen, uri, unicode, options
|
import strutils, times, macros, htmlgen, uri, unicode, options
|
||||||
import regex
|
import regex, packedjson
|
||||||
import types, utils, formatters
|
import types, utils, formatters
|
||||||
|
|
||||||
const
|
const
|
||||||
|
@ -11,9 +11,12 @@ const
|
||||||
|
|
||||||
let localTimezone = local()
|
let localTimezone = local()
|
||||||
|
|
||||||
|
template isNull*(js: JsonNode): bool = js.kind == JNull
|
||||||
|
template notNull*(js: JsonNode): bool = js.kind != JNull
|
||||||
|
|
||||||
template `?`*(js: JsonNode): untyped =
|
template `?`*(js: JsonNode): untyped =
|
||||||
let j = js
|
let j = js
|
||||||
if j == nil: return
|
if j.isNull: return
|
||||||
else: j
|
else: j
|
||||||
|
|
||||||
template `with`*(ident, value, body): untyped =
|
template `with`*(ident, value, body): untyped =
|
||||||
|
@ -24,8 +27,7 @@ template `with`*(ident, value, body): untyped =
|
||||||
template `with`*(ident; value: JsonNode; body): untyped =
|
template `with`*(ident; value: JsonNode; body): untyped =
|
||||||
block:
|
block:
|
||||||
let ident {.inject.} = value
|
let ident {.inject.} = value
|
||||||
if ident != nil and ident.kind != JNull:
|
if value.notNull: body
|
||||||
body
|
|
||||||
|
|
||||||
template getCursor*(js: JsonNode): string =
|
template getCursor*(js: JsonNode): string =
|
||||||
js{"content", "operation", "cursor", "value"}.getStr
|
js{"content", "operation", "cursor", "value"}.getStr
|
||||||
|
@ -50,7 +52,6 @@ proc getId*(id: string): string {.inline.} =
|
||||||
id[start + 1 ..< id.len]
|
id[start + 1 ..< id.len]
|
||||||
|
|
||||||
proc getId*(js: JsonNode): int64 {.inline.} =
|
proc getId*(js: JsonNode): int64 {.inline.} =
|
||||||
if js == nil: return
|
|
||||||
case js.kind
|
case js.kind
|
||||||
of JString: return parseBiggestInt(js.getStr("0"))
|
of JString: return parseBiggestInt(js.getStr("0"))
|
||||||
of JInt: return js.getBiggestInt()
|
of JInt: return js.getBiggestInt()
|
||||||
|
@ -117,10 +118,9 @@ template getSlice(text: string; slice: seq[int]): string =
|
||||||
text.runeSubStr(slice[0], slice[1] - slice[0])
|
text.runeSubStr(slice[0], slice[1] - slice[0])
|
||||||
|
|
||||||
proc getSlice(text: string; js: JsonNode): string =
|
proc getSlice(text: string; js: JsonNode): string =
|
||||||
if js == nil or js.kind != JArray or js.len < 2 or
|
if js.kind != JArray or js.len < 2 or js[0].kind != JInt: return text
|
||||||
js[0].kind != JInt: return text
|
|
||||||
|
|
||||||
let slice = js.to(seq[int])
|
let slice = @[js{0}.getInt, js{1}.getInt]
|
||||||
text.getSlice(slice)
|
text.getSlice(slice)
|
||||||
|
|
||||||
proc expandUrl(text: var string; js: JsonNode; tLen: int; hideTwitter=false) =
|
proc expandUrl(text: var string; js: JsonNode; tLen: int; hideTwitter=false) =
|
||||||
|
@ -130,9 +130,9 @@ proc expandUrl(text: var string; js: JsonNode; tLen: int; hideTwitter=false) =
|
||||||
|
|
||||||
let
|
let
|
||||||
url = js{"expanded_url"}.getStr
|
url = js{"expanded_url"}.getStr
|
||||||
slice = js{"indices"}.to(seq[int])
|
slice = js{"indices"}[1].getInt
|
||||||
|
|
||||||
if hideTwitter and slice[1] >= tLen and url.isTwitterUrl:
|
if hideTwitter and slice >= tLen and url.isTwitterUrl:
|
||||||
text = text.replace(u, "")
|
text = text.replace(u, "")
|
||||||
text.removeSuffix(' ')
|
text.removeSuffix(' ')
|
||||||
text.removeSuffix('\n')
|
text.removeSuffix('\n')
|
||||||
|
@ -178,7 +178,8 @@ proc expandProfileEntities*(profile: var Profile; js: JsonNode) =
|
||||||
proc expandTweetEntities*(tweet: Tweet; js: JsonNode) =
|
proc expandTweetEntities*(tweet: Tweet; js: JsonNode) =
|
||||||
let
|
let
|
||||||
orig = tweet.text
|
orig = tweet.text
|
||||||
slice = js{"display_text_range"}.to(seq[int])
|
textRange = js{"display_text_range"}
|
||||||
|
slice = @[textRange{0}.getInt, textRange{1}.getInt]
|
||||||
hasQuote = js{"is_quote_status"}.getBool
|
hasQuote = js{"is_quote_status"}.getBool
|
||||||
hasCard = tweet.card.isSome
|
hasCard = tweet.card.isSome
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue