瀏覽代碼

Misc. changes

Zed 6 年之前
父節點
當前提交
81d6d1ac7f
共有 6 個文件被更改,包括 126 次插入97 次删除
  1. 27 4
      src/formatters.nim
  2. 4 4
      src/nitter.nim
  3. 5 2
      src/prefs_impl.nim
  4. 1 1
      src/query.nim
  5. 88 86
      src/types.nim
  6. 1 0
      src/utils.nim

+ 27 - 4
src/formatters.nim

@@ -28,6 +28,7 @@ proc stripHtml*(text: string): string =
   for el in html.findAll("a"):
     let link = el.attr("href")
     if "http" in link:
+      if el.len == 0: continue
       el[0].text = link
   html.innerText()
 
@@ -94,9 +95,32 @@ proc getRfc822Time*(tweet: Tweet): string =
 proc getTweetTime*(tweet: Tweet): string =
   tweet.time.format("h:mm tt' · 'MMM d', 'YYYY")
 
-proc getLink*(tweet: Tweet | Quote; focus=true): string =
+proc getShortTime*(tweet: Tweet): string =
+  let
+    now = now().utc
+    then = tweet.time.utc
+    since = now - then
+
+  if now.year != then.year:
+    result = tweet.time.format("d MMM yyyy")
+  elif since.inDays >= 1:
+    result = tweet.time.format("MMM d")
+  elif since.inHours >= 1:
+    result = $since.inHours & "h"
+  elif since.inMinutes >= 1:
+    result = $since.inMinutes & "m"
+  elif since.inSeconds > 1:
+    result = $since.inSeconds & "s"
+  else:
+    # this shouldn't happen, but just in case
+    result = "now"
+
+proc getLink*(tweet: Tweet; focus=true): string =
   if tweet.id == 0: return
-  result = &"/{tweet.profile.username}/status/{tweet.id}"
+  var username = tweet.profile.username
+  if username.len == 0:
+    username = "i"
+  result = &"/{username}/status/{tweet.id}"
   if focus: result &= "#m"
 
 proc getTombstone*(text: string): string =
@@ -114,8 +138,7 @@ proc getTwitterLink*(path: string; params: Table[string, string]): string =
   let p = {
     "f": $query.kind,
     "q": genQueryParam(query),
-    "src": "typd",
-    "max_position": params.getOrDefault("max_position", "0")
+    "src": "typed_query"
   }
 
   result = $(parseUri("https://twitter.com") / path ? p)

+ 4 - 4
src/nitter.nim

@@ -3,7 +3,7 @@ from net import Port
 
 import jester
 
-import types, config, prefs, formatters, cache
+import types, config, prefs, formatters, redis_cache, tokens
 import views/[general, about]
 import routes/[
   preferences, timeline, status, media, search, rss, list,
@@ -13,8 +13,10 @@ const configPath {.strdefine.} = "./nitter.conf"
 let (cfg, fullCfg) = getConfig(configPath)
 
 updateDefaultPrefs(fullCfg)
-
+setCacheTimes(cfg)
 setHmacKey(cfg.hmacKey)
+initRedisPool(cfg)
+asyncCheck initTokenPool(cfg)
 
 createUnsupportedRouter(cfg)
 createResolverRouter(cfg)
@@ -27,8 +29,6 @@ createMediaRouter(cfg)
 createEmbedRouter(cfg)
 createRssRouter(cfg)
 
-asyncCheck cacheCleaner()
-
 settings:
   port = Port(cfg.port)
   staticDir = cfg.staticDir

+ 5 - 2
src/prefs_impl.nim

@@ -8,11 +8,14 @@ type
     name*: string
     label*: string
     kind*: PrefKind
-    options*: seq[string]
-    placeholder*: string
+    # checkbox
     defaultState*: bool
+    # select
     defaultOption*: string
+    options*: seq[string]
+    # input
     defaultInput*: string
+    placeholder*: string
 
   PrefList* = OrderedTable[string, seq[Pref]]
 

+ 1 - 1
src/query.nim

@@ -3,7 +3,7 @@ import strutils, strformat, sequtils, tables, uri
 import types
 
 const
-  separators = @["AND", "OR"]
+  # separators = @["AND", "OR"]
   validFilters* = @[
     "media", "images", "twimg", "videos",
     "native_video", "consumer_video", "pro_video",

+ 88 - 86
src/types.nim

@@ -1,68 +1,72 @@
-import times, sequtils, options
-import norm/sqlite
-
+import times, sequtils, options, tables
 import prefs_impl
 
 genPrefsType()
 
 type
+  Token* = ref object
+    tok*: string
+    limit*: int
+    remaining*: int
+    reset*: Time
+    init*: Time
+    # agent*: string
+
+  Error* = enum
+    protectedUser = 22
+    couldntAuth = 32
+    doesntExist = 34
+    notFound = 50
+    suspended = 63
+    invalidToken = 89
+    listIdOrSlug = 112
+    forbidden = 200
+    noCsrf = 353
+
+  Profile* = object
+    id*: string
+    username*: string
+    fullname*: string
+    lowername*: string
+    location*: string
+    website*: string
+    bio*: string
+    userpic*: string
+    banner*: string
+    following*: string
+    followers*: string
+    tweets*: string
+    likes*: string
+    media*: string
+    verified*: bool
+    protected*: bool
+    suspended*: bool
+    joinDate*: Time
+
   VideoType* = enum
-    vmap, m3u8, mp4
-
-dbTypes:
-  type
-    Profile* = object
-      username*: string
-      fullname*: string
-      lowername*: string
-      location*: string
-      website*: string
-      bio*: string
-      userpic*: string
-      banner*: string
-      following*: string
-      followers*: string
-      tweets*: string
-      likes*: string
-      media*: string
-      verified*: bool
-      protected*: bool
-      suspended*: bool
-      joinDate* {.
-          dbType: "INTEGER"
-          parseIt: it.i.fromUnix()
-          formatIt: dbValue(it.toUnix())
-        .}: Time
-      updated* {.
-          dbType: "INTEGER"
-          parseIt: it.i.fromUnix()
-          formatIt: dbValue(getTime().toUnix())
-        .}: Time
-
-    Video* = object
-      videoId*: string
-      contentId*: string
-      durationMs*: int
-      url*: string
-      thumb*: string
-      views*: string
-      available*: bool
-      reason*: string
-      title*: string
-      description*: string
-      playbackType* {.
-          dbType: "STRING"
-          parseIt: parseEnum[VideoType](it.s)
-          formatIt: dbValue($it)
-        .}: VideoType
-      updated* {.
-          dbType: "INTEGER"
-          parseIt: it.i.fromUnix()
-          formatIt: dbValue(getTime().toUnix())
-        .}: Time
+    m3u8 = "application/x-mpegURL"
+    mp4 = "video/mp4"
+    vmap = "video/vmap"
 
+  VideoVariant* = object
+    videoType*: VideoType
+    url*: string
+    bitrate*: int
+
+  Video* = object
+    videoId*: string
+    contentId*: string
+    durationMs*: int
+    url*: string
+    thumb*: string
+    views*: string
+    available*: bool
+    reason*: string
+    title*: string
+    description*: string
+    playbackType*: VideoType
+    variants*: seq[VideoVariant]
 
-type
   QueryKind* = enum
     posts, replies, media, users, tweets, userList
 
@@ -92,18 +96,20 @@ type
   Poll* = object
     options*: seq[string]
     values*: seq[int]
-    votes*: string
-    status*: string
+    votes*: int
     leader*: int
+    status*: string
 
   CardKind* = enum
+    player = "player"
     summary = "summary"
     summaryLarge = "summary_large_image"
     promoWebsite = "promo_website"
     promoVideo = "promo_video_website"
     promoVideoConvo = "promo_video_convo"
-    player = "player"
     liveEvent = "live_event"
+    broadcast = "broadcast"
+    periscope = "periscope_broadcast"
 
   Card* = object
     kind*: CardKind
@@ -113,25 +119,9 @@ type
     title*: string
     dest*: string
     text*: string
-    image*: Option[string]
+    image*: string
     video*: Option[Video]
 
-  Quote* = object
-    id*: int64
-    profile*: Profile
-    text*: string
-    reply*: seq[string]
-    hasThread*: bool
-    sensitive*: bool
-    available*: bool
-    tombstone*: string
-    thumb*: string
-    badge*: string
-
-  Retweet* = object
-    by*: string
-    id*: int64
-
   TweetStats* = object
     replies*: int
     retweets*: int
@@ -140,10 +130,10 @@ type
   Tweet* = ref object
     id*: int64
     threadId*: int64
+    replyId*: int64
     profile*: Profile
     text*: string
     time*: Time
-    shortTime*: string
     reply*: seq[string]
     pinned*: bool
     hasThread*: bool
@@ -151,27 +141,26 @@ type
     tombstone*: string
     location*: string
     stats*: TweetStats
-    retweet*: Option[Retweet]
+    retweet*: Option[Tweet]
     attribution*: Option[Profile]
     mediaTags*: seq[Profile]
-    quote*: Option[Quote]
+    quote*: Option[Tweet]
     card*: Option[Card]
+    poll*: Option[Poll]
     gif*: Option[Gif]
     video*: Option[Video]
     photos*: seq[string]
-    poll*: Option[Poll]
 
-  Result*[T] = ref object
+  Result*[T] = object
     content*: seq[T]
-    minId*: string
-    maxId*: string
-    hasMore*: bool
+    top*, bottom*: string
     beginning*: bool
     query*: Query
 
-  Chain* = ref object
+  Chain* = object
     content*: seq[Tweet]
     more*: int64
+    cursor*: string
 
   Conversation* = ref object
     tweet*: Tweet
@@ -181,6 +170,19 @@ type
 
   Timeline* = Result[Tweet]
 
+  List* = object
+    id*: string
+    name*: string
+    userId*: string
+    username*: string
+    description*: string
+    members*: int
+    banner*: string
+
+  GlobalObjects* = ref object
+    tweets*: Table[string, Tweet]
+    users*: Table[string, Profile]
+
   Config* = ref object
     address*: string
     port*: int

+ 1 - 0
src/utils.nim

@@ -8,6 +8,7 @@ const
   badPngExts = @["pngn", "png:", "png_", "_png"]
   twitterDomains = @[
     "twitter.com",
+    "pic.twitter.com",
     "twimg.com",
     "abs.twimg.com",
     "pbs.twimg.com",