Add support for business and gov verification
Also improve icon rendering on Firefox
This commit is contained in:
parent
d6be08d093
commit
f8254c2f0f
14 changed files with 59 additions and 31 deletions
|
@ -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",
|
||||
|
|
|
@ -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,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
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
button {
|
||||
margin: 0 2px 0 0;
|
||||
height: 23px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pref-input {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")):
|
||||
|
|
Loading…
Reference in a new issue