From 644e36b4eb56428e8b4770db5f30b11e22e1bf10 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sun, 17 Mar 2024 09:54:55 +0800 Subject: [PATCH] =?UTF-8?q?GUI=E6=8F=92=E4=BB=B6=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=89=98=E7=9B=98=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/msg-logging/config.py | 2 +- plugins/native-ui/config.py | 4 +- plugins/native-ui/data/blivechat.ico | Bin 0 -> 165662 bytes plugins/native-ui/ui/app.py | 12 +-- plugins/native-ui/ui/room_frame.py | 26 ++++--- plugins/native-ui/ui/task_bar_icon.py | 103 ++++++++++++++++++++++++++ plugins/text-to-speech/config.py | 2 +- 7 files changed, 129 insertions(+), 20 deletions(-) create mode 100644 plugins/native-ui/data/blivechat.ico create mode 100644 plugins/native-ui/ui/task_bar_icon.py diff --git a/plugins/msg-logging/config.py b/plugins/msg-logging/config.py index b0273fa..78e13a1 100644 --- a/plugins/msg-logging/config.py +++ b/plugins/msg-logging/config.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- import os -BASE_PATH = os.path.realpath(os.getcwd()) +BASE_PATH = os.path.dirname(os.path.realpath(__file__)) LOG_PATH = os.path.join(BASE_PATH, 'log') diff --git a/plugins/native-ui/config.py b/plugins/native-ui/config.py index 04e992a..5d5cc9a 100644 --- a/plugins/native-ui/config.py +++ b/plugins/native-ui/config.py @@ -8,7 +8,7 @@ import pubsub.pub as pub logger = logging.getLogger('native-ui.' + __name__) -BASE_PATH = os.path.realpath(os.getcwd()) +BASE_PATH = os.path.dirname(os.path.realpath(__file__)) LOG_PATH = os.path.join(BASE_PATH, 'log') DATA_PATH = os.path.join(BASE_PATH, 'data') @@ -18,6 +18,8 @@ CONFIG_PATH_LIST = [ os.path.join(DATA_PATH, 'config.example.ini') ] +BLC_ICON_PATH = os.path.join(DATA_PATH, 'blivechat.ico') + _config: Optional['AppConfig'] = None diff --git a/plugins/native-ui/data/blivechat.ico b/plugins/native-ui/data/blivechat.ico new file mode 100644 index 0000000000000000000000000000000000000000..3d1516477c0332c493200daf3cbde98e87cbcd3e GIT binary patch literal 165662 zcmeHw2YeGp+P+OoxrC5}OS|t9LLih7ItheOLg>ZxYST?`p(K>h!x2Jy=Pt=z+IQdo zE{WBvWn1ppU^>ROr0px)xMK|N^M6P3$^{v0Sq7IezhSjIyHlQdpLu8Ad1u$h#~1#c zJm~}fck#LZ{Wd;N`1ttrgaDU(KJ#^6ho3$^Tif`&(AUQi9OvXef&f8)AV3fx2oMAa z0t5kq06~BtKoB4Z5CjMUUP1t&xc2DgFCEG=f9rtIrFLFQmLyXT1Q4RzqSF6#D9HJH zhtk3zXovG1>hUo8y621%uA-Eo2L4u8~pt2!AmCb!Aplz zrsX{^n|E~1xbk}&FJ?`Wsz4y?MyjtZ;fn{Zgs*!xC3NKgF>L9$^pH7zX~qeD=^?ZH zGGaGO6(Uv*p+Yx5%S68aCjwmKBVdc!*M^PV|Bw*7uQy{_vzAuR`_-nLbct3D&kv_m%p96^G- zZ;>eLmrW~2TuL;~`;v}-_f_G{{s&qcW_P2$?3q1XxQJEn2+H9Jf_!j+2s{vjx>f`y zHzbZo*9BR3#3}pUB2Z7%D;^1e^da zxNQfiZMq^})~k$B3{R&tGZg73w~oubbnu~;iqXBO*QNM_k1?i2fr93ZL@}s4w8`@o z{Zvg}xI4$~1Z}8#{Yq-^qAeM5N1nbHb!hH+GGUwAa1lFR48|;Yx%rB-~+q)?e6s`0=d-< z0>Y^SzCyy`XBhRYPdVA^H=Vj%!rOzRd}yg%JM*WjXODEhdWOu`-9Ya4k{G_}e$l*s znxJ^&v>4Q<9=h9I8}%p^l#^|CG zc8q$?0bV|W_fETXMXYjUc8YHPSGJIqr0=RjyJX~twiTnd_2gA!&kC}Bj=4mo9Ym7% zdLPRL60gFv?UAK$BqpLgU`e*eqMhLw4XAB=nmvS_BLQ!l;$RJQOV zSrc)Cebr0JXFq+2irg_xkPo53HqyYcmBgcN<&0_qWz{WQQ#CL0`&I-p@@)@fWL|hA zBlBFRj4UafeW zN<6+7KaYdsIamF0c`EMDg7mX4Kspp1TY3Gwy@GM^A;Gxhuqy;FhTr~2c+;Y<1?4L?@3jkVtLKqjF_=#?E%-q+%>SEU zT!{0k7DPC=R|L`Ee;A)v4X*ofIh|#7#k=C9G!2Um3;Owo1;efRxVu-x_Zs0D>3P>N z;4tsVFQ9sylzx?ZILZv=7NodZ@|Nm^%jV1%p22yTpe=$SKV!fl&ba6!UN_Y!%KGGc zM~6H4!YhX%K|3kZuAjA^(azec?;4gZ<~`FPorzIxzF+BI z8CxW%Mj&236vC^BR}4YIEnzUk4FFqUe}~06mT&J*yfTi*CScoygDNEhm(gf>wQguDj9n#CaKQ}7y~r#Rp4Ik5RczO4Ke z#NoQ(GGnY{fR$Xrb_fzRuOVJHwvg3M5gGNAC{8!!XISrjp9x+zpEa!+D#q@5)=r;j zvh&Gn^iRG*^u7nUkj>8uVe7_POiPY|Pfk3o9GwF`2SqS$ErC!9zhP|;k704ZnAauT z4qtD?)ujv#y$6@Gu4&ZgUMbDnJ#)J_>3Mv--F-N&F~gn8A<2wGen5`8gHKVPLP{|{ zm(wkX0sGovK5Fe7wy2d)ix=O2AcOv{$@qAspWWTg9=E46XWj;W2Z6uxvNtV)tbZ=_ z14XcA3VdixTuIuk7hll-LA}ah+y_2hFXeKYQHfOel7DdVd&Y7xJ02AycieN^OG)}a z+ohk`GlC5b{DM+UIxonFfxhSiwkF&kV80F`zXXHEmI0@qmmu$5$|{FtSyYox(Wd2x z#pri>l!~ghw_1c6{|dVHci;S!_c{rYE0&7J=?XzLDvgs3sNe(P1>re(o)%owF)g#luE(i0BdyfGr z18IZWWx#2d13Pu1)wFOk9kt;Z@$4b5&q)fdeCNxYJkW(U1iZ^AMyJBM0od3in;>bQ z+S`X<(=@Q@RwgJ0S~&B{O>Ep&ukQcJx$uQ=_PNiVNH#8d+o~E3w%eD8-XMCjiOe~8o29Zr~$!1eYhf|G>x0u#1Wnzxi+XvXr8`^;H?Lb=R7Y)9h zu>MEZIGRekl5%*Xuj&eZ$pZ^%HTacB?R%b$Jz6iDuQg`-Ul~)t9`KRQbo$zQqf8_X zBHK+z1_W52;FTk-bja#mOxT8c`JhmyrDJH#lsHk=lg!D9y{?(ra_h=LZ1WvZ$f>4; z*dw;}%uM>OPWu$u`1hV>_49Ud@>gKL7=9O9UGpRN5v-b<47`Z<=<%FsYUR(MiM)u_|WdckAI$w{l)T=@J*_zo;fZ`0y1E^Wn?C z71X1^pQJwDW+L*_dgQ02w{^F2yK0y{RX2WpO@6StDIHnuxS!x1mlfa5YUx;z`Vn5& zlmYO^QoLR+80H);xv8)AJ?gZGZBH?hxKyua5Tz5fAw=*DsI9e4P4GSMBk z_9;YmS`Q{5|C)(rF=ERMF=DfWAAHoFhlQ|Bb4B@p6v7X}h1SCbcWn*d09Oq^mu8wB zm=-+S!4KG9_y}j-x>A%6rU*aWVMeaCD$dAWEE8qDeh_879eZwV5xY83p_^6<@6T?HukK$T>S2XGNL{}B}GN3sIVN} z%*#dm`HLt;^(_+RLm-`=5Xg6ao1rdo@xw;uA9d$LO`YT5$1zk|T!ipnIfNV6i%?E# zI!eD7iRhrUNcf`{r2m}fdDP64oZk&BUHq^DKPY0~^$hbG{BV#2{wo8b+{iCLS=Mt% zI30!rbs!SqUNPv;p5;S0akp`+#t$3ehiCZL!jGyv$;~N4*-7C@2>$^w%D2JJ{Y{KKNYWyJjqapK;%JG%Ni<-ys@^W-F^(NvH;!&z;FJgoIVcdo1CS=^zL^!w>UJZ;|m{p)4&K>3-5+~dpONz@;VNNPavrvdN z{~P8douC|Kywya;TP}VO`>uz&1NTP_;D^MS8#fWkOHV^rFPf1>`yw{$e;UP!7zz>Nh1=mZFXc5uX1Q}vf?;`H^*FmRrB(i&}?A{Gb z2tT}myBGO^c>-oGbhDrY3Fpru-uxrH3l`Q*{&)!F;VB5j9()(aUM_x+@s)?V1M|zv z{E#?OR$7X#<(9yhD*~nJS0h2S6!`HH1mgF2mpD?%4>G<2x$}@Cjld6Syj4~P>+r>e zC@&)qQD>6jy_d_t)&*m(Ab7_((IuX@S>4*&#Scr^&Q7*qvcJ|Njx-`aB%XjO0iUj7 zl%L9=6muA&<*;r-{8a8PKZt*cXL#QQepKa2&edxui%LR5#7~I+?;Mz$JPhR~^AeBx zw%hBGO8o)rAH@Hv>5Z=>Uer96fIi7hwWHK?5x|olfFHeqC)oG#uby%I_Hxo%({%B} z>0d(L59d)IbQkqUO`a5jOMRA@i8A88L!99_;$_o-Cw~HYCVPB6YRl^Vgo__E=nsax zAI`IW@*eU7^9B1o78e#HHYM9J<`UIQ5Fa!S>O$5Q8^{qCKb-z0M1OdM=RM|!lOqU~ zl$4>uf*VMI-^Vk3QC$Z&%KAsmaa3K;@!De1%_4Ly zBL}4?o<^)3)=h%2-y`9O2OM$f59j(I(H|aQ*rfO&@d)o-EG)Q*^7tggpFNFu&1OeA zoqMu8v_sVF7h3*#B|jYNgM=R~g&$RUl9yYKa%~BSkNzFe%Ka5~F5;_FhqkW953>Km z!+y01%s(VP)ON(B2zQ5Z7qN5Qh9@q5ko_MXas!VsngKsB zZ!kwnOF@^UXCYg7FcOUiVDI8c&?k5wJh64T;R)e~H^$J-gddV_DF>%6JcrLt%Ry-o zAA_CC4|oFm7s(ntU{I}}B>bq3M@@X{cHYeRA@QWN1lCRRvrrnHhL{LB)Row{2tTUz z4|S9OJ8`I)@#Ha!jDRsApEGr!gIN3X8eF@Iw~$IMfqtQO1+YZgy8op)<&N390PCQ*!0pM{P0Gb zG$VfCcW+(K%|}_Z715ew;HNbKIMIXf!o3_2ez?b_e)7@`_<{FV6~ja$of1&8QHezL zLhw6z1?u@?{p#usyqZrMgdg5$tES8k7);@P>~P_~s*RWUB z>?>;UgZP)+0k4|)InSFYKOB3gGT|MK=YB(c=r@Q{tf=rU`HTB{c%!dqS!uZVVFUjw zn(Y7ZOm3POKd^6Nes(TOyL<-OPX@u--Q(je<^o59Bl`&SX)5fA%?N`8>{?|R<1-eZ0^eA#c7p&MCgh>AahY^q~W z7yJ%iGWYh77m_Tv_(A*=J=7g|Y;lkHf%QdMX)(HycO9`;Qo-MFk7F$5+z&{273ZOQ(nyWBUp_(ANu9&!Ws$zI}zv_CvQ`x>%D$06SE9ugH3 zVU4dBaD(_t-DPfIT|@ZcjWLIp_>r4ahWN`?*c1K{ViX&J7x=wycuxkg*WLqe5Po=r z8(z>K*RR97*y-~q_2mCUwDvg6y`O-#0h=w+8CXW|Wgz;)8~A&mKVaz_<`^X?hqI#8 z3-L%W?5pr0#NT(mr!qnEuf(75qY?|x<)WVaC@L(4xi{FQEEkbY`99+R7zKHg?{+l7 zeu41gF7l(K1aty3GzbfD+xdD0zdHgIZBI*kjUPEci<{u zZ|i*cjt%ApS<7g`+`t@h@x!@(PQK6SQG4BHe1&xe{$5~4{P##OzK3|l0+@e43fPmi zZ;!C{Mt@fKG^+7~BHyo-^lJT%Zuo(}%ba&L2MK3lkv;04&hcP$uRn;Wv&l%% zZUH~S{?OL=yMJUIqnTq+$q&c(qsaW+v-SkvDA`aXDCfa(0PuqNgLsBxlj~0^`9a># z(7^s4`w#vP;YQ2SnJ#`<$^4^%{AhB0AE{5nx$5GF1;$r4V!t9X)o__=Nf;7-5P4`x z^6c%pxcEWFS7dzDLgv)oliT)t^;}#ik@q_4(Td*NI zpk?TQhP0!L9~Ky25&IS42+<+cWWdFbB;bdIeE*{%eGPfG<>{OMgLf*m^MSuB;d?rz zglt|d$OqHJKcZS6Lgc>X$^D(%RM!2bsOa&vsOZ@i^TQgmzY`U{El^Mlp$I<+KU)1b zOWW_15HWHIgf^HTT>PPqeAIS-Q8Cy`_(Ay5y7|!+3HsM#xYz{?_}KXlex$}9e$XEI z)&x=BKauc*@T1l9LpM2`kKH~~h~4VoNA88M?#qnXJ=8AmcY*MO@T0Z!L)1)B^0E6y z3Ni2c;_+1x^GDmPm_6M@);Us~gwjnui7$OY_G(2W0COgP%xe)>HJKQKoG z)fN`A-(bOLUKiL#!pq@QTL zGC;UrTibU-tYUOAqn)!KA**BU1M3d_XE82&$YNaj38x&9O5TlJ8-C<^%jQq7amW8$lOOmzMKixmiaua3qZ}&`8&*yH$azcVln~UjjFC@FXSDuv z;qxpmyH!=5Si@HNTEbTQvFfp*hIJ`$9+>1 zKk35iW_`oS@b~Y?H&buHk*pK8Nc+Dadnu0%3D`@W-1*n4oT&M`s4%#lO}At%qnyNo z4k;({LG(z=mVvJDJ(fOYHr05V4hUMmn8ONPG{16@f)^v+*%oSFF zzxhJ^-dnFcwY=JO6PtU)`EKsO>zP(fcwn`=77`FFwL4Ugd~iR?Cx- z*2;HYJ(1;1%XadYjy+nN{MY3=ZF;926S}i6r=9k{Fc-N-I6^qmygAjaoRhzn%^DVe z$;Iw_xh@>I(>>R0U$teT*3RMdQ%$gks)&rU2uGS9NATPLd=TY>uG89CL2TIi*K6~$ zx)UGV#b3)h(NPFn9>}XF!5;N~#l-i7aHM&01ao8H4Xb);gc!4NN+JJco!2_t@uB9m zqS9Y|#khTs*!4@6*;P}MMcK=sM~Ht`^OBL)%IR*f&M~Nn(oH!-o45E0@rOIrly7gH zr$+65f;X*P&T6J53bMYyk=BYisdsZ}dtN@Im{CuSq(U~#V50XwDxCkm&g+2nw@ll@PjWCKGe)5zEQ%8jTwgm#(2x zZ3N3_oo(h7b6K_DzXjRgG%=_P%zyBAj)|-g4DPiIU^#>_mFi79tC{mp-WWLkddg=H zN%DKQjs={mJ*|IhIIo%hDX$uJ1?*-O^LD}$!jZep5p17&9>G39n1{c5Lr}kQnlUc^ zfQj5O2%$*Fd)V(5FKXr^oO|)?z+k{}VN3^5<=I$&8X&v^YWo0 z_zqu(eOV<=t~4e_B<y`crPS=&T)_PzRG-X zoRluab%*r4!8vUIcBCt%E!71dE6VPukGuFP_u?|+x?pTv<#eXuIQN#F9j8;JJQ(X+ z^Q|bige@Gam#Ip*0q^QbT1ZyUM^yS#$2w7Z6fp6MFR;=Pe7ah0iX8pow zXNEJnDHkd2c&kDQEUCXF}!{Q2NQKHuV^Wf`E^X-@1u*+BhSJ zG0e!eso!KB*R&Hv#x&olZMuo6HVveun;_Cq4y$S`ZH0VT!?*&F3y{Tza0I?1A$z%uQ;sR1 z)Z^`rGOONzy1cs=Y%putXfl?{b@K)I!RDb*N; zQIF$T^|(w%H4OSu+($I9yz;(ftZwQxn`$CpF^0x?JMs;leT~wLWgTULa0F*?G{mB`m%_WI-XW3&tGBQ~IgtY{>cXLJ7tI?7TTQDbP$vJ`DaP3g6ZO;m6AiPL*dkW0qhr=>Vq!OJwnYZ6 zOEJw~maO;lPuBVQCpp42|K#AgOReUmt88IQ0+V&q1Mu|}!$fzAZ;pgA)p|&CS(1KwK(c8L;5>VA zl6LmOq-& z@a3zmVT%J(jI);Dvf=vP8m9VNLl&)|qt-z^02||MxOb|5vewVvrkfc+!#+cc_ zaJvDvR;VLR!_gj5Yc}AzB*XP2xX%)@a5)vZY8@4^VlA|1 z0OaYPSS|SZU)Ig=zpS6>f5k9&L9)Sr=4IoGH!p^58b~J`damS#_QCqdA-T6<2v`z! zJV%8s-p#5ffPX+w;D;yuG1eQv4ds-x$;MT0v6sH=+^|yJ{%JAQ*p80fKhUC|`#r0C z{VLus>KR9%FOUzo&KVZzY4heOwlg2sd%w`_OG;v!D+1`Ip$!+d^{=+DfPIW%VuRk> zBFG1nvWltaDb32w{FyI1@n^qk^f_Wu!m$p?aR>TQhPgkoir3Teywx*qLw_LaRmkdQ zYiaYQ8Fa$&M)SjHuCmhF%6&EdP+Ku(=U-UkvV**8oCW6Q9?BNjQ@|&U)%Yb-hQKw+ z=Fd9{XDh!S(b%|J5ye67{+L?oG zIP=CQY5kHzymB-iQ+fQ}VX!k6v8u_5oGCDnk3aI{y{IyqaJ)SewX+|kU+@*97zul# zv0ccMF(TF@eQxqPzhF9Y(_EW*<9$NH!A94E_X0DLXYB~sVm3Wv4GlQLDMtb~dU-e> zhxtZOzhYW3#I!U7DD$@GD82t)Rz2Dxc+3s(XOQ(TVU-il*|dRcY>`KvWKrHd zq8CPygPyF`rjO2eb8E!~Ovu8eN&z#)*GHsmu6RRAN0eaFyjsUM@ zy>2qv87f=Is;Mclgd-BhE#;Vc>C-ks+^+wz1us1WYtEGC+`x9KzQwF^TB1#}a?Rzi z&pM`F`liWoLuxncsYC6PT=naPrx0qG=B{PP=m2|}6&f(_ZCd&<}*^&~Dwr5W5 z8AKTtenZPfWW##{J)E;+yH@X;oMBd|Eq41tOXQaOq&`63`hY<-3^Ek6b}T;N6n z>{Kupr+^!*Y0XL@`oL3Z6e*sITs$LO1oZY36)Ls~Tq4f_K>5;Ixwsmhg?U zEa967MkMUBzM4CE@F|3{nhiIkW@ApC zXlD)EG{9z9^fjv(1$xBO`3Tsxd)#5ewn0=3xr~kLvaYJf0OX5Gk_PcWsty}na;K)@Wr~!5@S)Y7X zGf86!Tkn^6@&K`GNgy|aBV*qF9A#Lv8+^cl8+hM`C-aRLV1NI>QdT+XETdbxiHSSf z(U$OOv*m`=Z2Z|zIOEgRdiyhM@QOp6dNR{6I~A;pE2mwy8Ui<`UHIg2KH-CA&kd>7*pq*2&%_++LmTG* zz^X=qZ#*7rdDe%3UrrILo2jEGYkek?%Kl`CC8@=NZCfI);uL6H6_-3zX zZI1VDg0G=sMk1{Jt+b!s+xcqB4=sipQnRsfVAqO!yFYE5e*%0_@)~B>>Q%_;W@xF% zty8H}@7>e)AxQNj$La{sCwD){L~oxB+=z4f8hWx`4By-e>Q}@l{4Ozu)ysvLy)YLK zYjNC=kmIf#>%c^A9RTx@Phk&tuIK9`@I4L1umVaq;{+9d=&um!{XGq-Oyt-&2+*eG zooUn3?*+xHS)RR%3%<97_cp1fgCFj?wL;v%r?X+ry>Uw0bW#;Beczr5+dh!i1$<5` zM&^3D&W`slvZ^=ZEvEGgAhd5fH6$g$2=L)xuhLCF1%6Q;*l~dySZ~NDoT3b?wp_jR z(Nn10)N1;`)Jy*hdSvH7$~gb;jKdejlYNNzdwwHCO6&hVg!_q9HXQ^Iy3r;*Zf74x zH`d0>`_|JQ1Mi^>>R${t+<02OctiI2V~^!uZvJ+v`nFEG<^2vq!p;FU*sBZsN7DG9 z`hGJEeEsFGtgS4_o}0s76cPabN|MIY!# zYZrbCdL+Bo5(TAy!^40uqE&F%2$QD@B@FJfmKYq!iB6^ zZ9jG3neyv~R?iKoDeY&z?7*GeHjp+g_{!<8RX3kTK|LmdiQX}diP=Hs=MtDrB8stF|nHm zGsXpI9+M^nFZzaw+&H9`q{!tafI!yS6TX?}PdrQqub<6o=lm$ZS|O~5 zuz1ghpd6eks79P-HM9QD8oXh7>gf+2&bf4gaN`c`#w351F z7UcseQPH0g)x%Rn^{5cL$^ZSdnC*kHo#YP5k?1CX0Ll+)%O@P~!ba_!#T(`xhIero zIOEh$*vPH(`M6`<3xpq={5y=B0F168ChK=5RA8(xZAn@Z6&N%H)Y}B^<`1lWre~enC6!LA!q9gJSfG2ZV(E?fDBI5k2eyrsNTV06~BtKoB4Z5CjMU1Ob8o zL4Y7Y5FiK;1PB5I0fIn75rFTux&MQN-ABOHMvZ&FO19z7-%@^sJ_lTpr9Pt^zoj_F z=Q&qgq0fD_#^u(CGy6Q^dXDjFTkW}n75CzcW*^^baXuCI;)@5X$Cdk3oIB&3I98Oi z&T&$`DvqVnIZjjhU2%j%^}hqsJ&@Zie^OlTEipbALb!@6bn72L&sFrKx=-EKVC zSYuOjE#<`d)fRWBu{Tpon)o?S=LogUN$}jFwm3YOscjB)ySM|lc@9C`?dD@R-p!w5 zuI6@ni|6z3KrM03IVIyJMIW#c;OE@OIp?YF!FJAX-2>yC7rU(lm?3a}w~aHy9X0>J zBm$R^+lja|?{||Zwt6_8gCqQzaS{N$(@+8zs>C^eRxy55#=#Rfp@aBo=U-(UAb`y^ zW<2AsC5~|y2jYfJHvsN)w>(#IvEmjSU724+Mitpsk2~n&FfmoBVC8etugVHaS8(c1 z>kvF&vn;N(%+9o{mc>;D##KRAny#`}R?rm(w?F5|$8}R>{mfEQuEeXw9dJD7Dpa*N zM-;A1MeDlqGrJ602XBdUU4a&?`CO#|jkzVR((sn+Chob4vJ|?B8&wfkdP^MRG7y$a tW<6IO7^!8Tf)yq|S6rb>oYBFG)Ln6t)k71D`~PhIlaBxZ literal 0 HcmV?d00001 diff --git a/plugins/native-ui/ui/app.py b/plugins/native-ui/ui/app.py index b9c701f..ab8b9d2 100644 --- a/plugins/native-ui/ui/app.py +++ b/plugins/native-ui/ui/app.py @@ -6,9 +6,9 @@ import pubsub.pub as pub import wxasync import blcsdk.models as sdk_models -import listener import ui.room_config_dialog import ui.room_frame +import ui.task_bar_icon logger = logging.getLogger('native-ui.' + __name__) @@ -22,6 +22,8 @@ def init(): class App(wxasync.WxAsyncApp): def __init__(self, *args, **kwargs): + self._task_bar_icon: Optional[ui.task_bar_icon.TaskBarIcon] = None + super().__init__(*args, clearSigInt=False, **kwargs) self.SetExitOnFrameDelete(False) @@ -29,10 +31,12 @@ class App(wxasync.WxAsyncApp): self._room_config_dialog: Optional[ui.room_config_dialog.RoomConfigDialog] = None def OnInit(self): + self._task_bar_icon = ui.task_bar_icon.TaskBarIcon() + pub.subscribe(self._on_add_room, 'add_room') pub.subscribe(self._on_del_room, 'del_room') pub.subscribe(self._on_room_frame_close, 'room_frame_close') - pub.subscribe(self._on_open_admin_ui, 'open_admin_ui') + pub.subscribe(self._on_add_room, 'open_room') pub.subscribe(self._on_open_room_config_dialog, 'open_room_config_dialog') return True @@ -51,10 +55,6 @@ class App(wxasync.WxAsyncApp): def _on_room_frame_close(self, room_key: sdk_models.RoomKey): self._key_room_frame_dict.pop(room_key, None) - def _on_open_admin_ui(self): - for room in listener.iter_rooms(): - self._on_add_room(room.room_key) - def _on_open_room_config_dialog(self): if self._room_config_dialog is None or self._room_config_dialog.IsBeingDeleted(): self._room_config_dialog = ui.room_config_dialog.RoomConfigDialog(None) diff --git a/plugins/native-ui/ui/room_frame.py b/plugins/native-ui/ui/room_frame.py index b18fbc3..9b278c6 100644 --- a/plugins/native-ui/ui/room_frame.py +++ b/plugins/native-ui/ui/room_frame.py @@ -25,31 +25,35 @@ class RoomFrame(designer.ui_base.RoomFrameBase): room = listener.get_room(self._room_key) room_str = str(room.room_id) if room is not None else str(self._room_key) self.SetTitle(f'blivechat - 房间 {room_str}') - - self._apply_config(True) + self.SetIcon(wx.Icon(config.BLC_ICON_PATH, wx.BITMAP_TYPE_ICO)) self.super_chat_list.AppendColumn('时间', width=50) self.super_chat_list.AppendColumn('用户名', width=120) self.super_chat_list.AppendColumn('金额', width=50) self.super_chat_list.AppendColumn('内容', width=300) - for index in range(len(room.super_chats)): - self._on_super_chats_change(room, room.super_chats, index, True) self.gift_list.AppendColumn('时间', width=50) self.gift_list.AppendColumn('用户名', width=120) self.gift_list.AppendColumn('礼物名', width=100) self.gift_list.AppendColumn('数量', width=50) self.gift_list.AppendColumn('总价', width=50) - for index in range(len(room.gifts)): - self._on_gifts_change(room, room.gifts, index, True) # item_data只能存int,这里做个映射 self._uid_to_paid_user_item_data: Dict[str, int] = {} self._next_paid_user_item_data = 1 self.paid_user_list.AppendColumn('用户名', width=120) self.paid_user_list.AppendColumn('总付费', width=60) - for index in room.uid_paid_user_dict: - self._on_uid_paid_user_dict_change(room, room.uid_paid_user_dict, index, True) + + self._apply_config(True) + + if room is not None: + for index in range(len(room.super_chats)): + self._on_super_chats_change(room, room.super_chats, index, True) + for index in range(len(room.gifts)): + self._on_gifts_change(room, room.gifts, index, True) + for index in room.uid_paid_user_dict: + self._on_uid_paid_user_dict_change(room, room.uid_paid_user_dict, index, True) + self._on_simple_statistics_change(room) pub.subscribe(self._on_preview_room_opacity, 'preview_room_opacity') pub.subscribe(self._on_room_config_dialog_cancel, 'room_config_dialog_cancel') @@ -195,7 +199,7 @@ class RoomFrame(designer.ui_base.RoomFrameBase): # 模型事件 # - def _on_super_chats_change(self, room: listener.Room, value: List[listener.SuperChatRecord], index, is_new): # noqa + def _on_super_chats_change(self, room: listener.Room, value: List[listener.SuperChatRecord], index, is_new): if room.room_key != self._room_key: return @@ -243,7 +247,7 @@ class RoomFrame(designer.ui_base.RoomFrameBase): if height_to_bottom < last_row_rect.GetHeight() * 3: list_ctrl.Focus(last_row_index) - def _on_gifts_change(self, room: listener.Room, value: List[listener.GiftRecord], index, is_new): # noqa + def _on_gifts_change(self, room: listener.Room, value: List[listener.GiftRecord], index, is_new): if room.room_key != self._room_key: return @@ -260,7 +264,7 @@ class RoomFrame(designer.ui_base.RoomFrameBase): ] def _on_uid_paid_user_dict_change( - self, room: listener.Room, value: Dict[str, listener.PaidUserRecord], index, is_new # noqa + self, room: listener.Room, value: Dict[str, listener.PaidUserRecord], index, is_new ): if room.room_key != self._room_key: return diff --git a/plugins/native-ui/ui/task_bar_icon.py b/plugins/native-ui/ui/task_bar_icon.py new file mode 100644 index 0000000..cc15be6 --- /dev/null +++ b/plugins/native-ui/ui/task_bar_icon.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +import logging +import sys +import webbrowser + +import pubsub.pub as pub +import wx.adv + +import blcsdk +import config +import listener + +if sys.platform == 'win32': + IS_WIN = True + # 懒得引入pywin32了 + import ctypes + kernel32 = ctypes.windll.kernel32 + user32 = ctypes.windll.user32 +else: + IS_WIN = False + + +logger = logging.getLogger('native-ui.' + __name__) + + +class TaskBarIcon(wx.adv.TaskBarIcon): + def __init__(self): + super().__init__() + + self.SetIcon(wx.Icon(config.BLC_ICON_PATH, wx.BITMAP_TYPE_ICO), 'blivechat') + + self._menu = wx.Menu() + self._menu.Append(1, '打开所有房间窗口') + self._menu.Append(2, '打开主页') + if IS_WIN: + self._menu.Append(3, '隐藏/显示控制台') + self._menu.Append(wx.ID_SEPARATOR) + self._menu.Append(wx.ID_EXIT, '退出') + + self.Bind(wx.adv.EVT_TASKBAR_LEFT_UP, self._on_open_all_rooms_click) + self.Bind(wx.EVT_MENU, self._on_open_all_rooms_click, id=1) + self.Bind(wx.EVT_MENU, self._on_open_browser_click, id=2) + self.Bind(wx.EVT_MENU, self._on_hide_console_click, id=3) + self.Bind(wx.EVT_MENU, self._on_exit_click, id=wx.ID_EXIT) + + pub.subscribe(self._on_open_admin_ui, 'open_admin_ui') + + def _on_open_admin_ui(self): + self.PopupMenu(self.GetPopupMenu()) + + def GetPopupMenu(self): + return self._menu + + @staticmethod + def _on_open_browser_click(_event): + blc_port = blcsdk.get_blc_port() + url = 'http://localhost/' if blc_port == 80 else f'http://localhost:{blc_port}/' + webbrowser.open(url) + + @staticmethod + def _on_open_all_rooms_click(_event): + room_keys = [room.room_key for room in listener.iter_rooms()] + if not room_keys: + wx.MessageBox('没有任何已连接的房间', '提示') + return + + for room_key in room_keys: + pub.sendMessage('open_room', room_key=room_key) + + def _on_hide_console_click(self, _event): + assert IS_WIN + console_window_handle = self._find_console_window() + if console_window_handle == 0: + logger.warning('Console window not found') + wx.MessageBox('找不到控制台窗口', '提示') + return + + is_visible = user32.IsWindowVisible(console_window_handle) + show_param = 0 if is_visible else 5 # SW_HIDE SW_SHOW + user32.ShowWindowAsync(console_window_handle, show_param) + + @staticmethod + def _find_console_window(): + assert IS_WIN + console_window_handle: int = kernel32.GetConsoleWindow() + if console_window_handle == 0: + return 0 + # 兼容Windows Terminal,https://github.com/microsoft/terminal/issues/12464 + while True: + parent_window_handle: int = user32.GetParent(console_window_handle) + if parent_window_handle == 0: + break + console_window_handle = parent_window_handle + return console_window_handle + + def _on_exit_click(self, _event): + assert IS_WIN + # 先恢复控制台显示,防止退出后无法恢复 + console_window_handle = self._find_console_window() + if console_window_handle != 0 and not user32.IsWindowVisible(console_window_handle): + user32.ShowWindowAsync(console_window_handle, 5) # SW_SHOW + + kernel32.GenerateConsoleCtrlEvent(0, 0) # CTRL_C_EVENT diff --git a/plugins/text-to-speech/config.py b/plugins/text-to-speech/config.py index 16d0d2b..c1216de 100644 --- a/plugins/text-to-speech/config.py +++ b/plugins/text-to-speech/config.py @@ -6,7 +6,7 @@ from typing import * logger = logging.getLogger('text-to-speech.' + __name__) -BASE_PATH = os.path.realpath(os.getcwd()) +BASE_PATH = os.path.dirname(os.path.realpath(__file__)) LOG_PATH = os.path.join(BASE_PATH, 'log') DATA_PATH = os.path.join(BASE_PATH, 'data')