From b2d71407ba3009faf44d0249f55386aae578ae88 Mon Sep 17 00:00:00 2001 From: Cynthia Foxwell Date: Wed, 16 Apr 2025 13:34:35 -0600 Subject: [PATCH] brand labels, pcf labels, bookmark and view counts --- public/css/fontello.css | 130 +++++++++++++++++++++++++++--------- public/fonts/fontello.eot | Bin 9264 -> 10448 bytes public/fonts/fontello.svg | 42 +++++++----- public/fonts/fontello.ttf | Bin 9096 -> 10280 bytes public/fonts/fontello.woff | Bin 5752 -> 6568 bytes public/fonts/fontello.woff2 | Bin 4772 -> 5536 bytes src/consts.nim | 17 +++-- src/formatters.nim | 9 ++- src/nitter.nim | 4 +- src/parser.nim | 58 ++++++++-------- src/sass/general.scss | 66 ++++++++++-------- src/sass/profile/card.scss | 3 +- src/sass/tweet/_base.scss | 9 ++- src/types.nim | 9 +++ src/views/general.nim | 4 +- src/views/profile.nim | 9 ++- src/views/renderutils.nim | 8 ++- src/views/timeline.nim | 4 +- src/views/tweet.nim | 44 ++++++------ 19 files changed, 271 insertions(+), 145 deletions(-) diff --git a/public/css/fontello.css b/public/css/fontello.css index d022bb5..9ba8e6f 100644 --- a/public/css/fontello.css +++ b/public/css/fontello.css @@ -1,53 +1,121 @@ @font-face { - font-family: 'fontello'; - src: url('/fonts/fontello.eot?21002321'); - src: url('/fonts/fontello.eot?21002321#iefix') format('embedded-opentype'), - url('/fonts/fontello.woff2?21002321') format('woff2'), - url('/fonts/fontello.woff?21002321') format('woff'), - url('/fonts/fontello.ttf?21002321') format('truetype'), - url('/fonts/fontello.svg?21002321#fontello') format('svg'); + font-family: "fontello"; + src: url("/fonts/fontello.eot?76162212"); + src: + url("/fonts/fontello.eot?76162212#iefix") format("embedded-opentype"), + url("/fonts/fontello.woff2?76162212") format("woff2"), + url("/fonts/fontello.woff?76162212") format("woff"), + url("/fonts/fontello.ttf?76162212") format("truetype"), + url("/fonts/fontello.svg?76162212#fontello") format("svg"); font-weight: normal; font-style: normal; } - - [class^="icon-"]:before, [class*=" icon-"]:before { +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ +/* +@media screen and (-webkit-min-device-pixel-ratio:0) { + @font-face { + font-family: 'fontello'; + src: url('../font/fontello.svg?76162212#fontello') format('svg'); + } +} +*/ +[class^="icon-"]:before, +[class*=" icon-"]:before { font-family: "fontello"; font-style: normal; font-weight: normal; speak: never; - + display: inline-block; text-decoration: inherit; width: 1em; + margin-right: 0.2em; text-align: center; + /* opacity: .8; */ /* For safety - reset parent styles, that can break glyph codes*/ font-variant: normal; text-transform: none; - + /* fix buttons height, for twitter bootstrap */ line-height: 1em; - + + /* Animation center compensation - margins should be symmetric */ + /* remove if not needed */ + margin-left: 0.2em; + + /* you can be more comfortable with increased icons size */ + /* font-size: 120%; */ + /* Font smoothing. That was taken from TWBS */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + + /* Uncomment for 3D effect */ + /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } - -.icon-heart:before { content: '\2665'; } /* '♥' */ -.icon-quote:before { content: '\275e'; } /* '❞' */ -.icon-comment:before { content: '\e802'; } /* '' */ -.icon-ok:before { content: '\e803'; } /* '' */ -.icon-play:before { content: '\e804'; } /* '' */ -.icon-link:before { content: '\e805'; } /* '' */ -.icon-calendar:before { content: '\e806'; } /* '' */ -.icon-location:before { content: '\e807'; } /* '' */ -.icon-picture:before { content: '\e809'; } /* '' */ -.icon-lock:before { content: '\e80a'; } /* '' */ -.icon-down:before { content: '\e80b'; } /* '' */ -.icon-retweet:before { content: '\e80d'; } /* '' */ -.icon-search:before { content: '\e80e'; } /* '' */ -.icon-pin:before { content: '\e80f'; } /* '' */ -.icon-cog:before { content: '\e812'; } /* '' */ -.icon-rss-feed:before { content: '\e813'; } /* '' */ -.icon-info:before { content: '\f128'; } /* '' */ -.icon-bird:before { content: '\f309'; } /* '' */ + +.icon-heart:before { + content: "\2665"; +} /* '♥' */ +.icon-quote:before { + content: "\275e"; +} /* '❞' */ +.icon-ok:before { + content: "\e800"; +} /* '' */ +.icon-play:before { + content: "\e801"; +} /* '' */ +.icon-comment:before { + content: "\e802"; +} /* '' */ +.icon-link:before { + content: "\e803"; +} /* '' */ +.icon-calendar:before { + content: "\e804"; +} /* '' */ +.icon-picture:before { + content: "\e805"; +} /* '' */ +.icon-lock:before { + content: "\e806"; +} /* '' */ +.icon-down:before { + content: "\e807"; +} /* '' */ +.icon-retweet:before { + content: "\e808"; +} /* '' */ +.icon-search:before { + content: "\e809"; +} /* '' */ +.icon-pin:before { + content: "\e80a"; +} /* '' */ +.icon-cog:before { + content: "\e80b"; +} /* '' */ +.icon-info:before { + content: "\e80c"; +} /* '' */ +.icon-bookmark:before { + content: "\e80d"; +} /* '' */ +.icon-eye:before { + content: "\e80e"; +} /* '' */ +.icon-pcf:before { + content: "\e83a"; +} /* '' */ +.icon-location:before { + content: "\f031"; +} /* '' */ +.icon-bird:before { + content: "\f099"; +} /* '' */ +.icon-rss-feed:before { + content: "\f09e"; +} /* '' */ diff --git a/public/fonts/fontello.eot b/public/fonts/fontello.eot index aaddd6bf3959a71b00b92cd01dd4067db5d94b53..acc7a2074e87bee6e16685b4d81817fa60a34243 100644 GIT binary patch delta 3631 zcmZ`+eQZpN4gRvBpQ88N(t9G&wTJ$_E_QA=KBeOZbHbezLEU+ z-@l*wE6T4BLVw&hHR(q^UY>D$D0{~Dj_i(oj{crm6wQ0{2f1EFc@Vi_@9=$le)zLL zRuUqhtZp3~$oJPj#r{l)_6FKhgQ$>?vKLYQC(5;hBa_qHx-OT#AjIiI#kS$GzWnk~ zXgkW2D91+f)8lYd`55I3DEmkABLnX|r~=zKA@;Y13 zMB*jBtVb3ppB4$o2AnXM!mYL2(0S~5@rx+LR|wpZ7yFD(4> z`tz8Hz%vK7w;NNgD^A5zSW#FRa#gD@T!*$7T+95cR?N6n=T%qAxVm=~yGCRqB(}2( z%+5Y?M|SN%Z*Gl1gfue)R~NmYM^bKr#I8BlUu=OkOxf_j;JJByDhT3(c?AB zg8G1=U{)(#nnnwI$~*A^45dy)MUxZvt5uiOm~u_g=aREOhm%LfGjzK zC^W}eTvsshi0;2_tuyChQG-O)SygbWS+`p^`@FvFIXJ1kR3Wnov9>;s@wg&r4QeoM%-=gH^IU-8poC737L7FpZ)F2z?DnMp3E?YC3(-kK(Q!_4K0xE?eD_DqXv#5KC z&1kgs5}VDKCq|pGXLMws|Ms=5tANZFzBV;+VC2x~p`pS4;ep|Mc5K~}>ss4)dtat~ z)tc5d@uvFaZe6id7|BXl>B5P01SF?TEAUKVxk?6k;>yXxHCzM91TOm2;#(PzyfBo@ zK_tvK8YvJ?q{MO;ya!(IQV4>tbZx%XhArbg{kOLQ&Q9F!*F4SXonH5^um)6E9qy{2 zS|MAQ_cohqH9F#cyJ9!FYxU5bA-&dZvUhrGYZIXm_!k?#mTvZFU*Yq`qU%S{aI5Q% zD!0R0VGx4|*%R5QXW`jk5bmxCB(ojKT-W|wZm|yhgFQlj zK^n=%Y-g;Y&QC>A@?bgB?UV@>xafo&kwj^(*rV1KYIQwm3q)n9svawuQ&U(Z5aC$D zjbf3te7E}v6esTN62u}4D5x~++hKQD-R{+!!wsPZ&$>6p z#eJQdlI8>%g{tPFWoG9Z8e3PrGE*xl^bxw ztxM~oCiyT2o*CD;NQu<^b<2L69*a%gN+ Y*gZ7SZyrt`nJ z_!lq99{{kQkDQwElb(ulk1G3E{@CQv$hWVO{C5&<$I>VBq<511Cu+^dCSDo)^%Z^s zKuQ7FY}wItruJbpK_)#ku4hRh&+#iH&yn1eot!y6lzP5gCI!6^dM2hu(%v(*Z6YMHHw(tYxm*55d9K1({NT?JOHJs2wkZ9mHt79LK*05@!*1DpXfZ_yh z@|FYBMuUe+a;d81D0#lz@YrIwu%crnOKDBX{Y*zs7^SAt7%z6OTy@}wCeT1De!+r^ zWmbg+D6JZ~jj1XyC_~TPgsfCHDvg zF#If4RRBi2rUIbQmh2UPp>tFKhK|S@07K`gz{rO$H&g&FfXDO_1LXK>UQ_?E!^9E zJC#hvVo8AF+osv#4e?$Z%~SrA8-WoZ7EK(ZVOPS7UJPEnj!&*VJ#rPLtJiRude?|c zaYAfe+%Dh60)@5wIex_+kxyP|PqhlfJrW|r1&+WNP$p5nrD+Y=ey0OL@i@FrFWAv; z5^C5JRTbvIh!l_Mo~Rzv0zy&0%U(Q_>aqp~yY-9N&i?*$?S@xa3IZJnMpf2L~FNKy6 zZY`Z1+Iyogbbj{3g;`@_D8Izc@hVD!2y97hk|_>=J;Z@8fNT~FP=;}fi6LV+Y_!M@ zOJv0QT3b9FE+x=WUG1@obzzJfv8YFbjY$!~Ms7#BF%aa$G#Jx6T!9GciS-md5iGc( zD%z}0E8X}*)&9?VvqDXX#1Q7cGh3}@qxzj)#pQp?W^|xK zaqP@tLns--md+MjzMrc&^DF)quZN8gg&nEw%}tGUYik9^jarRYb#gE>?y#>Brh+7Z zaf&s^dBfFt@(9>G<;kgVs4WtThNJ#AFSzFWbs^@L zx9>c9^g@Om!CV3`qi=dqi^s|4)xmeet*7Ggbao+^&0KD2{ZZ!Ni?5xlEYG)W6Z-==3a}ZDe@sje zd-mOQ^be&pkZ2vGX`tL^I7^2cmrMq6;`@Dr_+f*1-`Z5LV#v<^AIssCC8&fOv?d|y z!p+r+pj_0pVodjTMAd>vv2)pu|D#THA$cF5<)*FGh7mfDI-(5>-?W<-EOxtP!D9QZ z)2G!|dmBhF+xCXm*Tn)&K4pV!mE|9pnKXQ(^@ZJ$cgYY}ow0^)V^YG3_L3y z!=4``Tp<{J1N7zKe!?70PCo-uTe@dEcR2cYSH~fTpCyHb0*VtY>=)HyQiyq%z zL{IThjTQqF{l84lm`=PrH8U!YOifOX=4RN`aVbBMenpxX&mA|9q$fsmne?>T_>-9# kpUM?KuG#1@PoF&5IyO3*k;ZdlQ_|7#>CB?7_K)`e0;>PssQ>@~ diff --git a/public/fonts/fontello.svg b/public/fonts/fontello.svg index 1f30ccc..53871b9 100644 --- a/public/fonts/fontello.svg +++ b/public/fonts/fontello.svg @@ -1,46 +1,52 @@ -Copyright (C) 2020 by original authors @ fontello.com +Copyright (C) 2025 by original authors @ fontello.com - + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + - \ No newline at end of file + diff --git a/public/fonts/fontello.ttf b/public/fonts/fontello.ttf index 29f1ec6d6ee124b4f25d2cad015933efaf7f982b..dcc56825cd1f7f290e48239e74cf83500c8221ae 100644 GIT binary patch delta 3661 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 UXN1Yz#EfucayD}-Q~R;~zZT`$B>(^b diff --git a/public/fonts/fontello.woff b/public/fonts/fontello.woff index 8428cf8cf6b3362734cae51568f5c293ef1e9eb8..8ec4ef8ca66276653d57d938b5e141f6c19d4273 100644 GIT binary patch delta 4549 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 Q_Yk|Rh-d;(*Yt@00aAlm`v3p{ delta 3738 zcmX|@1yEFN`^I+xS2~oGa9xl^@LkDeX^@syLg@}kfrTXxEg;Pc0xk^_(jbB~($XE$ z-5^NExBma%e9z1^=emE-ea~~wJacBQe7>`%)b46>av(4Ww`egSioZ|R&{%3gKpN+? zy+bs;&FoE_Kp^lWuI>YY@Dj0c<8)?ju27uM$1xI|$Z-N$I$7D{SQQ8a*~KAJQ^dKa zm5B>(mM90eP556?TG@G6;#d(*&L9veX=VogJ8KIQa}el06xYLx6Y{|hz$<8tqd2IE z1AjNz?grs!Slhc|aLg4~i{PXzsdam6=Vho<9M7~xhZASBk&2$m}HcsV!_1yG9UF; zBnwaz)e#huH=eTi@?CG!1U$`@Qm!H5e#teVw8N1>6Qy=3R}o_?dcIW%?;ifn{gE-+ z@hRiFOOM{@yUHcyb`1%6UIjV(K087O?SRG)gKTEKS@ZsY$8XlrMVnLH8&$<~@V@zz z3*c*7nzl~62n*(Ao^6JMDUI4VXIhDtDEdqO_G{VePR|F<1|a>k0T7?DO25T2cfQ-H^l{s5i$t7Exm2`~*jrb|u3{R){s_{gZfR(MTnNx?k?*2hX#Ny)G z>e}k!qJN)UvAENx6674y+eR>}v?Frsk8^EQX?C%@VNNMkLXe_+HWXxHt^$#pN+F>3 z>o=A*F>FIH5pGB^KWld5XgX4FMk3|me3{!=@J(q!KG8qWJ`&a zqR$9a5777UJDDajepu85Jkmj3XP-nA@^GrJQPn>ZTKVWRLc(3{>Au){x$We7(}Cr7 ze1eD3%m{Dx&a&h<#FQBWj!eIrgmpgE4gKCmT>4SLs5Yaznh{%LgfdX~Yj)B4axr)2 zpl!j7um;AJLtzJ=)H`8}yB6Umh?t^qLpK;9@%`$V27kYgH+>{VZxLOE(LyQmEr$6t zxAIL^iWfv-@xH_Jm;i;WDmfXcHV_mNR6+@+qME#C<1dAx4Uz_i=GQgdR{1Qwo)-NK z1;)!+LnzorIL+*!0h`d(r&vM;H=65a7RV5%3txnhkPeT(Nz^YHH*^9uF43jI2M z@9x7(zRzMFPqbOWTI9b@kHrpw^*+$?d(DqwM5jY%Zt5*lsw)pwRQUMLr++6*=Zg7P zq&MYQIkO_)c5VP+(+SgKKGlh8)?$~2k1$4t?M5nV3Tt6d;+PwdI!f+HQ#`^R<8WKV`Eh0wQKNWl0Tj% zUTTd^5=P%4YhO!t#U?@uc$N2;jt9>8QxT(d2a|L75_X8nm48H8%!qEYPQyaDwrpIL zK$mw^KcOL^jL9t_gC6`jcdx{unHkTPqAAJvseDML ztM?T=vN8k8kv!$1NV$E-t8x!uD$Sh+agy_GN*LZg1v_PY{xk>yoFl$t1xFG?Yf5HyE2O%*Gt{=Qoa;ZL_%R4yC zp~VXGFr17G&5TBnFnjoA1E3Gcc^ek{M(LKfk`2!iwn|2B_Kp`D`$@CUG4oN{SE&tB z?y;0Mw)As}YnkrRcb-ubaYvMWIJ$?5js=Pk3jtBWzmL}531lLp>t^N4f<;$m-whNo zB9Kj6Za<=DiO}P_4mS*Wvz2>is^Y$!$Af(IAD_i!c4QC*5M+~{2j(krozX}o2DuQc z!|)T-oaL&^;Q1#g6!$3i%PH#~!u7zy(Ko$W9jqmF8fdRSRc``XI!hFtg|SNwPXQeU z7eTdX@%$V&Ptm)=kH97k6UdEy%6=g9o&{ms6C=WZMfP&6Ml7uJ7M^@Wu{Kxse1>l} zW-lnad>DWpXk`9*|0-p%Lpg(Vm9Znz?N3^#i(2ISg|uVzp;)Qsz;;7kHRI{Zt1PiUtTZ(AuFRjqbbHvo$+7EH`+`@BU-Ee_o(PF{_F|qS|KhX*dzjf;c&>~e z2fKXQUU$1Xdmt9ggpR*A;YBJMAkp*HH?=EVMq{KaPAR8;qyK<*g9jYBfdSlg%5*4_ z8y1~N$nu@&g#AQVVZ1h<{UeA628Z;gHpi$kw091Zqn;k;`_ibLRcBsT;%gFlSDon) z7=NGE$jEiWRA;Mi|7Gw9b#oc={!c5cr_PFRUl`s45y;v@DD=YE~UUUJB?f! z##U2iUNe6INz?VGPhiUheniHnG$I!jhINk$8akt!swCH;I(+)J%K(kk8>9RBV~1#V z4>qcQUVT}PQhIGbL*tzZSNC$?TU|bG3%=8ehR|KnUejzTCz&gL)u7eu(x`ZD-Wpcb zMj~+VJTjg;ux%}jV8yTBR@KkeD(f}b;l<8mND@L%h|8eGlxY#asG~TurPEPco~wUE zi*i8xsQvoYye>-PApzi)If_P`9M*oUUZ=ytqh2QvPkXy>C77NbCG=b^U2L`oe=(Sy z*Gm#}KDi=C-hNhFnCp?h=qfOZOB@vSnGxifEprm|r@nv`!q{(wVE5QVf7u_OP`Y2z zyL;6)#Ln=v{nK^(4Qo^5oN3zHqwummiOfZayBH4sCZTXfTSL$l3 zy4!QM79dfrrvetUxi%$eTy_9P!-H9gm^jj6pK}@_`G(XDwJpxMh-oYx&=2QyJnxWY z{&}bw*br8cOqxH(Qo42b2Mw1B$fUbepLhF}$i?NOI^|m#Vsl3`YaPUl zRC(`L2C1fI0)Q@#?5OJNW$U79#nKXw&Uu`~dm9dxQI!v+bZkQPl@bD;yPR3p2bb~2 zGDR1ifAdiO|B|mi%>Y~dr2vkq|qml*WnTHDE)g`u_>d+}IejL^(T_e0YU4 zVmM1S0?E=lq@VARW#8W3rgxh*Gm)-1b94L4;C?i+>;KJ=U!=D;H)r8`ZU>%1NF}ML zp`@Thb_f?P_4&3mH#6b4k@%h6p(epA$D{nl&CTs=Vr)Egd;5^RGm9ce7GR)HN`ZPN zk%P(wV#EUd!Jun1(r{d8#4S#cHK+>I3)%u(g9q^_@xt+z@agf>@RtY_2paFu-pPVM zaETI^zddI3SSc9-bI`B z0{Iz{$+7WbGFPhKu1KCN-e9$Q$G7G&lDes}T82(Pzu#z&vlis@{^*JF-7_?88Nt*2 zY4AlaWlKBYy@Wu}_3L64YnW&0R(S4iM&D`r?ImRNRgf$OYu`I_F91p{XW}dSNW`ji zNSewno@y!trRtc@H+y1G^5HS@;YjGMt~oWwBaO_EfDUr96VyWJ{r;MTa7Nurt!)q6$R9n2w58e%q6NLA(F;AxK2o-kE)U(Cu(dR4+6v}u!?)g*SXJ@1; fo|tGP+;^1C>O9;TwK@Wax6xS&aX{la8GQc(@J`J< diff --git a/public/fonts/fontello.woff2 b/public/fonts/fontello.woff2 index 551f49d02d766d86f92cf78bc80f94379da58c6e..be42172992bb560cd4daed53e9b3c4089c8a1cd8 100644 GIT binary patch literal 5536 zcmV;R6<_LiPew8T0RR9102QDB4*&oF04OK`02N070RR9100000000000000000000 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 literal 4772 zcmV;V5?k$ePew8T0RR9101~7C4*&oF03(P101`?70RR9100000000000000000000 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 diff --git a/src/consts.nim b/src/consts.nim index 4d5c0b6..dc0cbe0 100644 --- a/src/consts.nim +++ b/src/consts.nim @@ -17,8 +17,8 @@ const graphql = api / "graphql" graphUser* = graphql / "32pL5BWe9WKeSK1MoPvFQQ/UserByScreenName" graphUserById* = graphql / "5vdJ5sWkbSRDiiNZvwc2Yg/UserByRestId" - graphUserTweets* = graphql / "3JNH4e9dq1BifLxAa3UMWg/UserWithProfileTweetsQueryV2" - graphUserTweetsAndReplies* = graphql / "8IS8MaO-2EN6GZZZb8jF0g/UserWithProfileTweetsAndRepliesQueryV2" + graphUserTweets* = graphql / "M3Hpkrb8pjWkEuGdLeXMOA/UserTweets" + graphUserTweetsAndReplies* = graphql / "pz0IHaV_t7T4HJavqqqcIA/UserTweetsAndReplies" graphUserMedia* = graphql / "dexO_2tohK86JDudXXG3Yw/UserMedia" graphTweet* = graphql / "y90SwUGBZ3yz0yNUmCHgTw/TweetDetail" graphTweetResult* = graphql / "sITyJdhRPpvpEjg4waUmTA/TweetResultByIdQuery" @@ -95,7 +95,7 @@ const "unified_cards_ad_metadata_container_dynamic_card_content_query_enabled": false, "verified_phone_label_enabled": false, "vibe_api_enabled": false, - "view_counts_everywhere_api_enabled": false, + "view_counts_everywhere_api_enabled": true, "premium_content_api_read_enabled": false, "responsive_web_grok_analyze_button_fetch_trends_enabled": false, "responsive_web_grok_analysis_button_from_backend": false, @@ -108,7 +108,8 @@ const "responsive_web_twitter_article_notes_tab_enabled": false, "subscriptions_feature_can_gift_premium": false, "hidden_profile_subscriptions_enabled": true, - "subscriptions_verification_info_is_identity_verified_enabled": true + "subscriptions_verification_info_is_identity_verified_enabled": true, + "responsive_web_grok_show_grok_translated_post": false }""".replace(" ", "").replace("\n", "") tweetVariables* = """{ @@ -131,9 +132,13 @@ const }""".replace(" ", "").replace("\n", "") userTweetsVariables* = """{ - "rest_id": "$1", + "userId": "$1", $2 - "count": 20 + "count": 20, + "includePromotedContent": false, + "withCommunity": true, + "withQuickPromoteEligibilityTweetFields": false, + "withVoice": true }""".replace(" ", "").replace("\n", "") listTweetsVariables* = """{ diff --git a/src/formatters.nim b/src/formatters.nim index 8e5fa47..c7c0d7e 100644 --- a/src/formatters.nim +++ b/src/formatters.nim @@ -7,6 +7,7 @@ const cards = "cards.twitter.com/cards" tco = "https://t.co" twitter = parseUri("https://twitter.com") + sameProto = "//" let twRegex = re"(?<=(? 0 and ("reddit.com" in result or "redd.it" in result): result = result.replace(rdShortRegex, prefs.replaceReddit & "/comments/") diff --git a/src/nitter.nim b/src/nitter.nim index 1f4c7d9..a813490 100644 --- a/src/nitter.nim +++ b/src/nitter.nim @@ -14,7 +14,7 @@ import routes/[ activityspoof] const instancesUrl = "https://github.com/zedeus/nitter/wiki/Instances" -const issuesUrl = "https://github.com/zedeus/nitter/issues" +const issuesUrl = "https://gitlab.com/Cynosphere/nitter/issues" #let accountsPath = getEnv("NITTER_ACCOUNTS_FILE", "./guest_accounts.json") @@ -80,7 +80,7 @@ routes: error InternalError: echo error.exc.name, ": ", error.exc.msg - const link = a("open a GitHub issue", href = issuesUrl) + const link = a("open an issue", href = issuesUrl) resp Http500, showError( &"An error occurred, please {link} with the URL you tried to visit.", cfg) diff --git a/src/parser.nim b/src/parser.nim index 1759e8c..c691792 100644 --- a/src/parser.nim +++ b/src/parser.nim @@ -39,14 +39,28 @@ proc parseGraphUser*(js: JsonNode): User = result = parseUser(user{"legacy"}, user{"rest_id"}.getStr) let label = user{"affiliates_highlighted_label", "label"} - if not label.isNull and label{"userLabelType"}.getStr == "AutomatedLabel": - result.bot = true - let entities = label{"longDescription", "entities"} - if not entities.isNull: - for ent in entities: - if ent{"ref", "type"}.getStr != "TimelineRichTextMention": continue - result.botOwner = ent{"ref", "screen_name"}.getStr - break + if not label.isNull: + let labelType = label{"userLabelType"}.getStr + if labelType == "AutomatedLabel": + result.bot = true + let entities = label{"longDescription", "entities"} + if not entities.isNull: + for ent in entities: + if ent{"ref", "type"}.getStr != "TimelineRichTextMention": continue + result.botOwner = ent{"ref", "screen_name"}.getStr + break + # TODO: are there other types than the two + # TODO: find profile with "userLabelDisplayType" not equal to "Badge" + elif labelType == "BusinessLabel": + result.badge = Badge( + name: label{"description"}.getStr, + icon: label{"badge", "url"}.getStr, + url: label{"url", "url"}.getStr + ) + + let pcf = user{"parody_commentary_fan_label"}.getStr + if pcf.len > 0 and pcf != "None": + result.pcf = pcf if result.verifiedType == VerifiedType.none and user{"is_blue_verified"}.getBool(false): result.verifiedType = blue @@ -230,7 +244,8 @@ proc parseTweet(js: JsonNode; jsCard: JsonNode = newJNull()): Tweet = replies: js{"reply_count"}.getInt, retweets: js{"retweet_count"}.getInt, likes: js{"favorite_count"}.getInt, - quotes: js{"quote_count"}.getInt + quotes: js{"quote_count"}.getInt, + bookmarks: js{"bookmark_count"}.getInt ) ) @@ -491,6 +506,11 @@ proc parseGraphTweet(js: JsonNode; isLegacy=false): Tweet = note.expandBirdwatchEntities(communityNote{"subtitle"}) result.birdwatch = some(note) + if not js{"views", "count"}.isNull: + result.stats.views = parseInt(js{"views", "count"}.getStr) + else: + result.stats.views = -1 + proc parseGraphThread(js: JsonNode): tuple[thread: Chain; self: bool] = for t in js{"content", "items"}: let entryId = t{"entryId"}.getStr @@ -562,28 +582,12 @@ proc parseGraphTimeline*(js: JsonNode; root: string; after=""): Profile = let instructions = if root == "list": ? js{"data", "list", "timeline_response", "timeline", "instructions"} - elif root == "user": ? js{"data", "user_result", "result", "timeline_response", "timeline", "instructions"} else: ? js{"data", "user", "result", "timeline", "timeline", "instructions"} if instructions.len == 0: return for i in instructions: - if i{"__typename"}.getStr == "TimelineAddEntries": - for e in i{"entries"}: - let entryId = e{"entryId"}.getStr - if entryId.startsWith("tweet"): - with tweetResult, e{"content", "content", "tweetResult", "result"}: - let tweet = parseGraphTweet(tweetResult, false) - if not tweet.available: - tweet.id = entryId.getId() - result.tweets.content.add tweet - elif "-conversation-" in entryId or entryId.startsWith("homeConversation"): - let (thread, self) = parseGraphThread(e) - result.tweets.content.add thread.content - elif entryId.startsWith("cursor-bottom"): - result.tweets.bottom = e{"content", "value"}.getStr - # TODO cleanup if i{"type"}.getStr == "TimelineAddEntries": for e in i{"entries"}: let entryId = e{"entryId"}.getStr @@ -598,8 +602,8 @@ proc parseGraphTimeline*(js: JsonNode; root: string; after=""): Profile = result.tweets.content.add thread.content elif entryId.startsWith("cursor-bottom"): result.tweets.bottom = e{"content", "value"}.getStr - if after.len == 0 and i{"__typename"}.getStr == "TimelinePinEntry": - with tweetResult, i{"entry", "content", "content", "tweetResult", "result"}: + if after.len == 0 and i{"type"}.getStr == "TimelinePinEntry": + with tweetResult, i{"entry", "content", "itemContent", "tweet_results", "result"}: let tweet = parseGraphTweet(tweetResult, false) tweet.pinned = true if not tweet.available and tweet.tombstone.len == 0: diff --git a/src/sass/general.scss b/src/sass/general.scss index 9feb3d3..debf89f 100644 --- a/src/sass/general.scss +++ b/src/sass/general.scss @@ -1,39 +1,49 @@ -@import '_variables'; -@import '_mixins'; +@import "_variables"; +@import "_mixins"; .panel-container { - margin: auto; - font-size: 130%; + margin: auto; + font-size: 130%; } .error-panel { - @include center-panel(var(--error_red)); - text-align: center; + @include center-panel(var(--error_red)); + text-align: center; } .search-bar > form { - @include center-panel(var(--darkest_grey)); + @include center-panel(var(--darkest_grey)); - button { - background: var(--bg_elements); - color: var(--fg_color); - border: 0; - border-radius: 3px; - cursor: pointer; - font-weight: bold; - width: 30px; - height: 30px; - } + button { + background: var(--bg_elements); + color: var(--fg_color); + border: 0; + border-radius: 3px; + cursor: pointer; + font-weight: bold; + width: 30px; + height: 30px; + } - input { - font-size: 16px; - width: 100%; - background: var(--bg_elements); - color: var(--fg_color); - border: 0; - border-radius: 4px; - padding: 4px; - margin-right: 8px; - height: unset; - } + input { + font-size: 16px; + width: 100%; + background: var(--bg_elements); + color: var(--fg_color); + border: 0; + border-radius: 4px; + padding: 4px; + margin-right: 8px; + height: unset; + } +} + +.brand-badge { + margin-left: 4px; +} +.brand-badge-image { + width: 16px; + height: 16px; + border: 1px solid var(--accent_border); + margin-bottom: -4px; } diff --git a/src/sass/profile/card.scss b/src/sass/profile/card.scss index f3e25f5..781ddae 100644 --- a/src/sass/profile/card.scss +++ b/src/sass/profile/card.scss @@ -83,7 +83,8 @@ .profile-joindate, .profile-location, .profile-website, - .profile-automated { + .profile-automated, + .profile-pcf { color: var(--fg_faded); margin: 1px 0; width: 100%; diff --git a/src/sass/tweet/_base.scss b/src/sass/tweet/_base.scss index 513d4f4..e5e8667 100644 --- a/src/sass/tweet/_base.scss +++ b/src/sass/tweet/_base.scss @@ -47,6 +47,11 @@ display: flex; justify-content: space-between; } +.tweet-label-row { + padding: 0; + display: flex; + gap: 0.4em; +} .fullname-and-username { display: flex; @@ -69,10 +74,10 @@ word-wrap: normal; } -.user-automated { +.user-automated, +.user-pcf { @include ellipsis; min-width: 1px; - margin-left: 0.4em; color: var(--fg_faded); } diff --git a/src/types.nim b/src/types.nim index 496e300..b3c69e2 100644 --- a/src/types.nim +++ b/src/types.nim @@ -80,6 +80,11 @@ type business = "Business" government = "Government" + Badge* = object + name*: string + icon*: string + url*: string + User* = object id*: string username*: string @@ -101,6 +106,8 @@ type joinDate*: DateTime bot*: bool botOwner*: string + pcf*: string + badge*: Badge VideoType* = enum m3u8 = "application/x-mpegURL" @@ -203,6 +210,8 @@ type retweets*: int likes*: int quotes*: int + bookmarks*: int + views*: int BirdwatchNote* = ref object id*: string diff --git a/src/views/general.nim b/src/views/general.nim index 6e96a0c..82197da 100644 --- a/src/views/general.nim +++ b/src/views/general.nim @@ -55,7 +55,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc=""; buildHtml(head): link(rel="stylesheet", type="text/css", href="/css/style.css?v=20") - link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=2") + link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=3") link(rel="stylesheet", href="/css/baguetteBox.min.css") script(src="/js/baguetteBox.min.js", `async`="") script(src="/js/zoom.js") @@ -183,7 +183,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc=""; # this is last so images are also preloaded # if this is done earlier, Chrome only preloads one image for some reason link(rel="preload", type="font/woff2", `as`="font", - href="/fonts/fontello.woff2?21002321", crossorigin="anonymous") + href="/fonts/fontello.woff2?76162212", crossorigin="anonymous") proc renderMain*(body: VNode; req: Request; cfg: Config; prefs=defaultPrefs; titleText=""; desc=""; ogTitle=""; rss=""; video=""; diff --git a/src/views/profile.nim b/src/views/profile.nim index 62b3c3b..625294c 100644 --- a/src/views/profile.nim +++ b/src/views/profile.nim @@ -26,8 +26,8 @@ proc renderUserCard*(user: User; prefs: Prefs; path: string): VNode = tdiv(class="profile-card-tabs-name-and-follow"): tdiv(): - linkUser(user, class="profile-card-fullname") - linkUser(user, class="profile-card-username") + linkUser(user, class="profile-card-fullname", prefs) + linkUser(user, class="profile-card-username", prefs) let following = isFollowing(user.username, prefs.following) if not following: buttonReferer "/follow/" & user.username, "Follow", path, "profile-card-follow-button" @@ -44,6 +44,11 @@ proc renderUserCard*(user: User; prefs: Prefs; path: string): VNode = else: icon "cog", "Automated" + if user.pcf.len > 0: + tdiv(class="profile-pcf"): + span: + icon "pcf", &"{user.pcf} account" + if user.bio.len > 0: tdiv(class="profile-bio"): p(dir="auto"): diff --git a/src/views/renderutils.nim b/src/views/renderutils.nim index 310d283..87ecf84 100644 --- a/src/views/renderutils.nim +++ b/src/views/renderutils.nim @@ -1,7 +1,7 @@ # SPDX-License-Identifier: AGPL-3.0-only import strutils, strformat import karax/[karaxdsl, vdom, vstyles] -import ".."/[types, utils] +import ".."/[types, utils, formatters] const smallWebp* = "?name=small&format=webp" @@ -30,7 +30,7 @@ template verifiedIcon*(user: User): untyped {.dirty.} = else: text "" -proc linkUser*(user: User, class=""): VNode = +proc linkUser*(user: User, class="", prefs: Prefs): VNode = let isName = "username" notin class href = "/" & user.username @@ -44,6 +44,10 @@ proc linkUser*(user: User, class=""): VNode = if user.protected: text " " icon "lock", title="Protected account" + if user.badge.name.len > 0: + span(class="brand-badge"): + a(href=replaceUrls(user.badge.url, prefs), title=user.badge.name): + img(class="brand-badge-image", src=user.badge.icon, alt=user.badge.name) proc linkText*(text: string; class=""): VNode = let url = if "http" notin text: https & text else: text diff --git a/src/views/timeline.nim b/src/views/timeline.nim index 34a6e4e..a941965 100644 --- a/src/views/timeline.nim +++ b/src/views/timeline.nim @@ -74,8 +74,8 @@ proc renderUser*(user: User; prefs: Prefs): VNode = tdiv(class="tweet-name-row"): tdiv(class="fullname-and-username"): - linkUser(user, class="fullname") - linkUser(user, class="username") + linkUser(user, class="fullname", prefs) + linkUser(user, class="username", prefs) tdiv(class="tweet-content media-body", dir="auto"): verbatim replaceUrls(user.bio, prefs) diff --git a/src/views/tweet.nim b/src/views/tweet.nim index f990cb4..1ad0866 100644 --- a/src/views/tweet.nim +++ b/src/views/tweet.nim @@ -15,32 +15,40 @@ proc renderMiniAvatar(user: User; prefs: Prefs): VNode = img(class=(prefs.getAvatarClass & " mini"), src=url) proc renderHeader(tweet: Tweet; retweet: string; pinned: bool; prefs: Prefs): VNode = + let user = tweet.user + buildHtml(tdiv): if pinned: tdiv(class="pinned"): - span: icon "pin", "Pinned Tweet" + span: icon "pin", "Pinned" elif retweet.len > 0: tdiv(class="retweet-header"): span: icon "retweet", retweet & " retweeted" tdiv(class="tweet-header"): - a(class="tweet-avatar", href=("/" & tweet.user.username)): + a(class="tweet-avatar", href=("/" & user.username)): var size = "_bigger" - if not prefs.autoplayGifs and tweet.user.userPic.endsWith("gif"): + if not prefs.autoplayGifs and user.userPic.endsWith("gif"): size = "_400x400" - genImg(tweet.user.getUserPic(size), class=prefs.getAvatarClass) + genImg(user.getUserPic(size), class=prefs.getAvatarClass) tdiv(class="tweet-name-row"): tdiv(class="fullname-and-username"): - linkUser(tweet.user, class="fullname") - linkUser(tweet.user, class="username") - if tweet.user.bot: - tdiv(class="user-automated"): icon "cog", "Automated" + linkUser(user, class="fullname", prefs) + linkUser(user, class="username", prefs) span(class="tweet-date"): a(href=getLink(tweet), title=tweet.getTime): text tweet.getShortTime + if user.pcf.len > 0 or user.bot: + tdiv(class="tweet-label-row"): + if user.bot: + tdiv(class="user-automated"): icon "cog", "Automated" + + if user.pcf.len > 0: + tdiv(class="user-pcf"): icon "pcf", &"{user.pcf} account" + proc renderAlbum(tweet: Tweet): VNode = let groups = if tweet.photos.len < 3: @[tweet.photos] @@ -185,7 +193,7 @@ func formatStat(stat: int): string = if stat > 0: insertSep($stat, ',') else: "" -proc renderStats(stats: TweetStats; views: string; tweet: Tweet): VNode = +proc renderStats(stats: TweetStats; tweet: Tweet): VNode = buildHtml(tdiv(class="tweet-stats")): a(href=getLink(tweet)): span(class="tweet-stat"): icon "comment", formatStat(stats.replies) @@ -193,11 +201,10 @@ proc renderStats(stats: TweetStats; views: string; tweet: Tweet): VNode = span(class="tweet-stat"): icon "retweet", formatStat(stats.retweets) a(href="/search?q=quoted_tweet_id:" & $tweet.id): span(class="tweet-stat"): icon "quote", formatStat(stats.quotes) - a(): - span(class="tweet-stat"): icon "heart", formatStat(stats.likes) - a(href=getLink(tweet)): - if views.len > 0: - span(class="tweet-stat"): icon "play", insertSep(views, ',') + a(): span(class="tweet-stat"): icon "heart", formatStat(stats.likes) + a(): span(class="tweet-stat"): icon "bookmark", formatStat(stats.bookmarks) + if stats.views > -1: + a(): span(class="tweet-stat"): icon "eye", formatStat(stats.views) proc renderReply(tweet: Tweet): VNode = buildHtml(tdiv(class="replying-to")): @@ -248,8 +255,8 @@ proc renderQuote(quote: Tweet; prefs: Prefs; path: string): VNode = tdiv(class="tweet-name-row"): tdiv(class="fullname-and-username"): renderMiniAvatar(quote.user, prefs) - linkUser(quote.user, class="fullname") - linkUser(quote.user, class="username") + linkUser(quote.user, class="fullname", prefs) + linkUser(quote.user, class="username", prefs) span(class="tweet-date"): a(href=getLink(quote), title=quote.getTime): @@ -322,7 +329,6 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; index=0; a(class="tweet-link", href=getLink(tweet)) tdiv(class="tweet-body"): - var views = "" renderHeader(tweet, retweet, pinned, prefs) if not afterTweet and index == 0 and tweet.reply.len > 0 and @@ -347,10 +353,8 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; index=0; if tweet.video.isSome: renderVideo(tweet.video.get(), prefs, path) - views = tweet.video.get().views elif tweet.gif.isSome: renderGif(tweet.gif.get(), prefs) - views = "GIF" if tweet.poll.isSome: renderPoll(tweet.poll.get()) @@ -368,7 +372,7 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; path: string; class=""; index=0; renderMediaTags(tweet.mediaTags) if not prefs.hideTweetStats: - renderStats(tweet.stats, views, tweet) + renderStats(tweet.stats, tweet) if showThread: a(class="show-thread", href=("/i/status/" & $tweet.threadId)):