Explorar o código

Add support for business and gov verification

Also improve icon rendering on Firefox
Zed %!s(int64=2) %!d(string=hai) anos
pai
achega
f8254c2f0f

+ 4 - 6
src/consts.nim

@@ -29,12 +29,10 @@ const
     "include_cards": "1",
     "include_entities": "1",
     "include_profile_interstitial_type": "0",
-    "include_quote_count": "1",
-    "include_reply_count": "1",
-    "include_user_entities": "1",
-    "include_ext_reply_count": "1",
-    "include_ext_is_blue_verified": "1",
-    # "include_ext_verified_type": "1",
+    "include_quote_count": "0",
+    "include_reply_count": "0",
+    "include_user_entities": "0",
+    "include_ext_reply_count": "0",
     "include_ext_media_color": "0",
     "cards_platform": "Web-13",
     "tweet_mode": "extended",

+ 3 - 2
src/experimental/parser/graphql.nim

@@ -1,7 +1,7 @@
 import options
 import jsony
 import user, ../types/[graphuser, graphlistmembers]
-from ../../types import User, Result, Query, QueryKind
+from ../../types import User, VerifiedType, Result, Query, QueryKind
 
 proc parseGraphUser*(json: string): User =
   if json.len == 0 or json[0] != '{':
@@ -14,7 +14,8 @@ proc parseGraphUser*(json: string): User =
 
   result = raw.data.userResult.result.legacy
   result.id = raw.data.userResult.result.restId
-  result.verified = result.verified or raw.data.userResult.result.isBlueVerified
+  if result.verifiedType == none and raw.data.userResult.result.isBlueVerified:
+    result.verifiedType = blue
 
 proc parseGraphListMembers*(json, cursor: string): Result[User] =
   result = Result[User](

+ 1 - 2
src/experimental/parser/unifiedcard.nim

@@ -1,7 +1,6 @@
 import std/[options, tables, strutils, strformat, sugar]
 import jsony
-import user
-import ../types/unifiedcard
+import user, ../types/unifiedcard
 from ../../types import Card, CardKind, Video
 from ../../utils import twimg, https
 

+ 1 - 1
src/experimental/parser/user.nim

@@ -56,7 +56,7 @@ proc toUser*(raw: RawUser): User =
     tweets: raw.statusesCount,
     likes: raw.favouritesCount,
     media: raw.mediaCount,
-    verified: raw.verified or raw.extIsBlueVerified,
+    verifiedType: raw.verifiedType,
     protected: raw.protected,
     joinDate: parseTwitterDate(raw.createdAt),
     banner: getBanner(raw),

+ 2 - 2
src/experimental/types/user.nim

@@ -1,5 +1,6 @@
 import options
 import common
+from ../../types import VerifiedType
 
 type
   RawUser* = object
@@ -15,8 +16,7 @@ type
     favouritesCount*: int
     statusesCount*: int
     mediaCount*: int
-    verified*: bool
-    extIsBlueVerified*: bool
+    verifiedType*: VerifiedType
     protected*: bool
     profileLinkColor*: string
     profileBannerUrl*: string

+ 3 - 3
src/parser.nim

@@ -21,7 +21,7 @@ proc parseUser(js: JsonNode; id=""): User =
     tweets: js{"statuses_count"}.getInt,
     likes: js{"favourites_count"}.getInt,
     media: js{"media_count"}.getInt,
-    verified: js{"verified"}.getBool or js{"ext_is_blue_verified"}.getBool,
+    verifiedType: parseEnum[VerifiedType](js{"verified_type"}.getStr("None")),
     protected: js{"protected"}.getBool,
     joinDate: js{"created_at"}.getTime
   )
@@ -34,8 +34,8 @@ proc parseGraphUser(js: JsonNode): User =
     user = ? js{"user_results", "result"}
   result = parseUser(user{"legacy"})
 
-  if "is_blue_verified" in user:
-    result.verified = user{"is_blue_verified"}.getBool()
+  if result.verifiedType == none and user{"is_blue_verified"}.getBool(false):
+    result.verifiedType = blue
 
 proc parseGraphList*(js: JsonNode): List =
   if js.isNull: return

+ 1 - 0
src/redis_cache.nim

@@ -52,6 +52,7 @@ proc initRedisPool*(cfg: Config) {.async.} =
     await migrate("profileDates", "p:*")
     await migrate("profileStats", "p:*")
     await migrate("userType", "p:*")
+    await migrate("verifiedType", "p:*")
 
     pool.withAcquire(r):
       # optimize memory usage for user ID buckets

+ 2 - 0
src/sass/include/_variables.scss

@@ -28,6 +28,8 @@ $more_replies_dots: #AD433B;
 $error_red: #420A05;
 
 $verified_blue: #1DA1F2;
+$verified_business: #FAC82B;
+$verified_government: #C1B6A4;
 $icon_text: $fg_color;
 
 $tab: $fg_color;

+ 18 - 3
src/sass/index.scss

@@ -39,6 +39,8 @@ body {
     --error_red: #{$error_red};
 
     --verified_blue: #{$verified_blue};
+    --verified_business: #{$verified_business};
+    --verified_government: #{$verified_government};
     --icon_text: #{$icon_text};
 
     --tab: #{$fg_color};
@@ -141,17 +143,30 @@ ul {
 
 .verified-icon {
     color: var(--icon_text);
-    background-color: var(--verified_blue);
     border-radius: 50%;
     flex-shrink: 0;
     margin: 2px 0 3px 3px;
-    padding-top: 2px;
-    height: 12px;
+    padding-top: 3px;
+    height: 11px;
     width: 14px;
     font-size: 8px;
     display: inline-block;
     text-align: center;
     vertical-align: middle;
+
+    &.blue {
+        background-color: var(--verified_blue);
+    }
+
+    &.business {
+        color: var(--bg_panel);
+        background-color: var(--verified_business);
+    }
+
+    &.government {
+        color: var(--bg_panel);
+        background-color: var(--verified_government);
+    }
 }
 
 @media(max-width: 600px) {

+ 2 - 0
src/sass/search.scss

@@ -14,6 +14,8 @@
     button {
         margin: 0 2px 0 0;
         height: 23px;
+        display: flex;
+        align-items: center;
     }
 
     .pref-input {

+ 8 - 4
src/types.nim

@@ -10,9 +10,7 @@ type
   BadClientError* = object of CatchableError
 
   TimelineKind* {.pure.} = enum
-    tweets
-    replies
-    media
+    tweets, replies, media
 
   Api* {.pure.} = enum
     tweetDetail
@@ -63,6 +61,12 @@ type
     tweetUnavailable = 421
     tweetCensored = 422
 
+  VerifiedType* = enum
+    none = "None"
+    blue = "Blue"
+    business = "Business"
+    government = "Government"
+
   User* = object
     id*: string
     username*: string
@@ -78,7 +82,7 @@ type
     tweets*: int
     likes*: int
     media*: int
-    verified*: bool
+    verifiedType*: VerifiedType
     protected*: bool
     suspended*: bool
     joinDate*: DateTime

+ 1 - 1
src/views/general.nim

@@ -52,7 +52,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
   let opensearchUrl = getUrlPrefix(cfg) & "/opensearch"
 
   buildHtml(head):
-    link(rel="stylesheet", type="text/css", href="/css/style.css?v=18")
+    link(rel="stylesheet", type="text/css", href="/css/style.css?v=19")
     link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=2")
 
     if theme.len > 0:

+ 12 - 5
src/views/renderutils.nim

@@ -23,6 +23,13 @@ proc icon*(icon: string; text=""; title=""; class=""; href=""): VNode =
     if text.len > 0:
       text " " & text
 
+template verifiedIcon*(user: User): untyped {.dirty.} =
+  if user.verifiedType != none:
+    let lower = ($user.verifiedType).toLowerAscii()
+    icon "ok", class=(&"verified-icon {lower}"), title=(&"Verified {lower} account")
+  else:
+    text ""
+
 proc linkUser*(user: User, class=""): VNode =
   let
     isName = "username" notin class
@@ -32,11 +39,11 @@ proc linkUser*(user: User, class=""): VNode =
 
   buildHtml(a(href=href, class=class, title=nameText)):
     text nameText
-    if isName and user.verified:
-      icon "ok", class="verified-icon", title="Verified account"
-    if isName and user.protected:
-      text " "
-      icon "lock", title="Protected account"
+    if isName:
+      verifiedIcon(user)
+      if user.protected:
+        text " "
+        icon "lock", title="Protected account"
 
 proc linkText*(text: string; class=""): VNode =
   let url = if "http" notin text: https & text else: text

+ 1 - 2
src/views/tweet.nim

@@ -200,8 +200,7 @@ proc renderAttribution(user: User; prefs: Prefs): VNode =
   buildHtml(a(class="attribution", href=("/" & user.username))):
     renderMiniAvatar(user, prefs)
     strong: text user.fullname
-    if user.verified:
-      icon "ok", class="verified-icon", title="Verified account"
+    verifiedIcon(user)
 
 proc renderMediaTags(tags: seq[User]): VNode =
   buildHtml(tdiv(class="media-tag-block")):