From 1f1148020c3421bf8d5b902e3da8421a3a171252 Mon Sep 17 00:00:00 2001 From: Andy <88590076+AAndyProgram@users.noreply.github.com> Date: Fri, 27 Jan 2023 16:43:57 +0300 Subject: [PATCH] 2023.1.27.0 Plugins: added 'Interaction' to 'Provider' attribute; added 'IPropertyProvider' interface Hosts: update classes to work with new options Instagram: fixed pinned post reload Twitter: advanced options for GIFs UserCreatorForm: change icon based on the selected site UserSearchForm: change search function --- Changelog.md | 14 ++ ProgramScreenshots/SettingsSiteTwitter.png | Bin 16160 -> 19758 bytes .../Attributes/Attributes.vb | 2 + .../Interfaces/IPropertyProvider.vb | 13 ++ .../My Project/AssemblyInfo.vb | 4 +- .../SCrawler.PluginProvider.vbproj | 1 + SCrawler/API/Base/UserDataBase.vb | 8 +- SCrawler/API/Instagram/UserData.vb | 23 +-- SCrawler/API/Twitter/Declarations.vb | 1 + SCrawler/API/Twitter/EditorExchangeOptions.vb | 27 ++++ SCrawler/API/Twitter/OptionsForm.Designer.vb | 148 ++++++++++++++++++ SCrawler/API/Twitter/OptionsForm.resx | 143 +++++++++++++++++ SCrawler/API/Twitter/OptionsForm.vb | 78 +++++++++ SCrawler/API/Twitter/SiteSettings.vb | 56 ++++++- SCrawler/API/Twitter/UserData.vb | 44 +++++- SCrawler/Editors/UserCreatorForm.vb | 12 ++ SCrawler/My Project/AssemblyInfo.vb | 4 +- .../Hosts/PropertyValueHost.vb | 28 +++- .../PluginsEnvironment/Hosts/SettingsHost.vb | 16 +- SCrawler/SCrawler.vbproj | 10 ++ SCrawler/UserSearchForm.vb | 47 +++--- 21 files changed, 617 insertions(+), 62 deletions(-) create mode 100644 SCrawler.PluginProvider/Interfaces/IPropertyProvider.vb create mode 100644 SCrawler/API/Twitter/EditorExchangeOptions.vb create mode 100644 SCrawler/API/Twitter/OptionsForm.Designer.vb create mode 100644 SCrawler/API/Twitter/OptionsForm.resx create mode 100644 SCrawler/API/Twitter/OptionsForm.vb diff --git a/Changelog.md b/Changelog.md index 353eb58..85798f3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,17 @@ +# 2023.1.27.0 + +*2023-01-27* + +- Added + - Advanced Twitter options for GIFs + - Changing the icon of the user creation form based on the selected site +- Fixed + - Pinned Instagram posts reload every time +- Plugins + - Added + - `Interaction` option to the `Provider` attribute + - `IPropertyProvider` interface + # 2023.1.24.1 *2023-01-24* diff --git a/ProgramScreenshots/SettingsSiteTwitter.png b/ProgramScreenshots/SettingsSiteTwitter.png index fa555832595c3a12c5cb8590cb578ae423be67bb..224880cb046ff0fdefc24252ef70942a8f3d197d 100644 GIT binary patch literal 19758 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 literal 16160 zcmdtJXIN9)x;BiC&WkupoqPr~(4gn+B!#h=2r;4n_z? zq!WrXLreH(EbFYj&OU3u=X?LXKfGp$bB;0Q7*DyM=e`rAqoquGk^UkP5fQ1X3Pg{H z=npUv(W(0v&H>+W8DFmjE~mWol;w%w{fsNXA7>ooH06kh-X@S7-#rWbP5eN`)QgCS ztex=hRF`{+EfLYJ8dZp#fxp#y7HPAEUC5FHdc79?+Gjnq(GrF7t$A(dy8d`11O6#O zbn^A8_*4DyE@OwKG__3 zmDt_4$>rqeI7ecjVL)O@V#m{KGwWm4ru*T#%#y@FK!19-PxfX=wnN15c`k%0utXxs zN7S%}VjL&%@!j*sP~dXA>ox?qytKIrye-k-^~)gOvU~-40l0Wyf}8;^k{_VaNU3Rj z*Y+obDSMdbcSYg30WQvkDz0O!fedg1QK20ueecr=Ynbp!Rhvyu&Oksyvwi2?fH9u| z6RVc(=PwSUQnrKAzW44rjXYig9=Pp3QVD&5r-f0+Zbw!m`=wgvNPh3%#?05jCsI_P z0}O&_usbeOyJ+<^aI>HAw{JHZzK*bvFzfF=|3u70GE@oGkeK@j5e!{YC#S!D@UVHO z@1&18^Ol{b+O1&xml5$^sgvb8uXP^lY5uk~#768LTsW3L4YyrCd6@m~I&iBUmM$TU9Nt9`w2zkX8On=#S^z;xAWm+>!-MZ zm>9^7p0t+QP4scS07D}!FredEuB+`Smw^q}p9$;9{h8Wu&-J z)p8Qml_bWtWW7`yBDYm%{uy;6>4up}!XLonavv-p_J{?lCeHaW6ke2@*_5+or{c-_ z{FbepvQV~(;8Nzckoyfg+6J7+yb&8mz=0!}xpe5+%~D-zKW1Qn>gc4)xE1%v)f;&N zAl>O>n4R1Ta{GvOhDKU8R_LtOO$}4E|U;thJD2;R7{*J}Fr+-7-az7Zsh8PrS zXWds;m)`>(CyI77CmbS?(#4;Ca1Kn^L#ERp;6ES6Kl+dE6AOXFGf5HR$F-urxtB_U z!Ua~_WA@!!VUCN!tR;7HQ04L2vJ=A{J_Ii@-mEBc`o!3F>AQD zLnU~-gHrp&wN}wsrA#tNLD$e#aQNlnDLKeX=U*S4*uhVpJn`IJ)(yZPEG;~xwR$6s z+a0O&+nhFN;fG#`C8mdjUzTr_>Vw#x;BlVc2KBdT(`Gmj-|?7*;Z-Av;N9ZNAgtSX zgO|hOY?j0bFleZ@N z{PCX0Bm3K_TG#9-Qx`E!XDS$2q*nC4O^V@no?nyGsDUL|wFe2DPwm&X6gl1$i?xN1 z+|&$Zp-@`IzekzN&LC2|o*xT~?YCUDO&(E!e804j6jV#zGr_W!$RIAuTk#?+zxnvp zt%G4r^ZC4iP%WAlhP=Y_oviO(WEWNTD3En`(o^w%t__{21ZYbt=h2=Kn3KN`(L%;gihL{+CSMd+FLIv~ zJnm(-ai;55+may0u64yRDXr($=0Q<)pJ>p=v_}hhh-Fgi)NxSZ#w=ub5h1s=`Q&8N z?D#0Tpc4~uLTa(=<2YC2huW=}THHa2wsOfU3B^Hd(eXIp^+ZzPa?j%62jiRp<3~o_ z>L-CIOwuwY@Gt{*HL9Rx+uwtr!xqWefQH7O2mBT=4z|P`$X|_Tn zSz*5du)Y@>1{}PKdV84t*dl1b^yrBDw*~~!)B!Jx2YG{4p>0S@a0~wIX4XrE6<={L z%b?Z`^!9=9OttPXCIfdM*=M6{(j3oeXvM;T%qn-~WYgFRDPCQ+UR@OOZF=2>@yj2$ zF42YA+X=&cDt@_$`4)V5_Tywu*vy2-0oGQl8cT(sd5T@jo*8sbRa*@Z^WSI-L;0iK zXIzf3?$!}&VlKLiVq0jHuaKNl_cz&&j*nfj7R^gHt3w`F zoMN?krUb5B$(0K@a%dI6Ef#ODAF-q<+YoO#`9UDX)`v$&cKt6TguNCuOyAsjME%TZ zq-Y#QA(L&%_ZYA}y7Usm{M?W!t?B1JJw==;p3N0LYYi}iyh`IPXSBkI1%w{A;5v=O z9c~;KWbM~mGp}BDX$aCfcM>=4eM|i{RR>dx(1kr_F~jV}$oWZ)N}prr23Nn6(jadv zyj$8YPD`dkFF(s3C+6%qv+>ktg!gTA;l$WJcI_mVy!hT`O}AGaDq(ZT`+MNP9=fM? zb8KY4%L|2U=2T?}6<%+chcl>bn0%Re_u~=k2}~c;q!&D z+fDO^I|$aJ9BIz31ev6yXTFLM-R?n9f`EA~a(89KZn!{I*k{$iw8}n?QNoj*i}fOS zShGZ9ee4+d zMeC9kszYetlgE*3@_=}j>UM@b=1kpQfTQIO<7qag(xvRE_|ocK+ zPl($h;!JM4M1G+cXpFGVem(cyoEH_ZDivRERH8Lh%SpF_yqJ!i^oo*dw=jR?e5Bfw zIpx)ce9SrKD<{?HDs^vtc@C4Fqi)HyYAwW`SL(dKWtF6pRq$$jXGF9f%RarAxEzok zspR5nxsE+@GKX6B@rrdp4>7^cu$6rA^ z1*OcDq1ERYnZIOP;k41|GjRw*OixylUqe4mYM`jd)PiWGq$4di-d3Y+ zW8a;iTGw<}?C6fGx2dl<`*Z=g=|^_N!!;E`d`%EbXDBUuEQ#L=?gIWW`2igm@WPiFLJPaoz{J#jc8G z6cPIDL1f@RBt&g^!MwzWX|4}!@9uZULt-E7gkSd5D~3Ursk#9?afRw~B%E?+k7*qW z&HD>R07d{-`JgSoxx*#( zFD1!8LopdLVCb!+!K34DGVt)6qgu`}F;LD((1%!)heQFe>feJaio?J?->t&Cq7&X% z!7}lGS>Oj+m|iKBJ4pV*N~$OYtgTH>B5=1v`s8?L`#p(}Np|R=(|D7gdzlptOFhBSc(*c_pbPn4sgFbJ!PVUg+;3N^|JUMUjr9CDE5BI&oj z6M$`+5g@;{e@BO29-LR{@#Wnq3IA^|*U)tXsiom1yN(TfJ1cIWQo{llN!4|3^@U1< zvPY6^Pp!%=U}noE;)5S>&X)-Z*Q-=Cx!1d)Yh&bMzMfbw;QP} zFkPodp(?YfSomifn0@1y(OOtXsrEt=06B_ zH>?P3Stc`ma$VRWde}Xbcc%5kBS19ua*nSu#QU%ifv{fun9e5R(4TykgvR7l`VH3% zCZ3_W@fz?HAGqtj9#0y3nL**Ak|N`nqhn8zK`K&fT=a_Ebu`SW{8lGr;cET1XM;<; zountaLAlf`36!pp32!#KzFvPMjD-*6S`|H-@-(FKWUWk{Aa`wiwEFjh z4#%H1KotcIH8AG5+nva{V)eYe1 zZhUitu3L4Cl+n+%V1jrpbA8gQpHWC!{K-#$(*mNqY^X)Q40iHG@O}woat9X_DJE9s zgE2~%@`E!GN97?^`uO>7Nvh@LbIdv3=Zs;{gcjeKw8oc`p@>zAp7h5{*KgZ1`RQia zFLAO-jDukBwhRJvo6Zi5S6KVIHE;fkMEdODNOG3iocqMYPzBmdE5E6-yFx};(gBtH zR?Q~o&YiREjHdQ&LDrkUGRsN5vZ@lP1X-0A77c-A>kaLAw?t;<(V00XQm55V=2&(6 zPMV4P2(%R2>x*ou#3tp9BGtdt%kt{^w>(~2>s2z6t~_G?(+Yk>dv`lFcGjMi;vB&o z{H}v-cUo$-7&y-7pL$Y)NR;OPb*Pkul8%j9ds+TEj z+j~DS?u^dPY?UPxfgjxe&ohG-Z46TN_LKf#gDd$Mr{4hslm%}1_MYU)A72N3z>Tf> zQ=MhJ%%-ys9)AUjMHpqSGGQ7OY#|IM6uI>Emb zrqB!C0`$1E=ZGF|DCKWrCdLz};1w5`7zE*(=Ye2;S^ff@EOE;~&f4Ef>c4iZ{+=HG zC6A~iHSgBNccM1?xm4>3M=>;r{iO=@U@pG%0P%C5w-vU!74%e z`=Ej+Hd2;;2_lYwUa3aSHU(KuPIc=y%#wOEmBL&NIp5Myaq4)sD9ZVa&mxqRiY(?ibjb z+(q74EowuR1Jx*FOFFvZEZ7$)7uCNCLY;e2;Vvs z8LwR1P43=wJ9|9f>G4hy3MrP>tbD_5;%bxcy2h9@JJ`*v=pS+l6lpS~!TfQngwgNK zf=XFjkG`v6-$Xc_i#bI5)5~SYjl$5SMmP)Ub3ZgZ!I`3 z5o@a|>!iY$l4Qa!-y4pGO1C-Ttb7!i}lO7Qp#UGQKJorTk0U0LrO6 zCek6@#C+w1a~L+TjUpSUo7oE(U)`?CRnnS|KX)$F;dROL(asNoiLVVbTlSkT(OW|@ z;Gpj4r|Pwnw9$E$_I(+4%F4g1pDU!FprRD<@}Q^!`WQt6ftwrsy?W(p z9K$>rpOhfO^00K~w^5yK)Y;3U8Z8f0BonvSd@LH8vIQPJ7-qdS!AK74ybqkNxGo zzQ|eqYkfubE)3b;>+IZK)~+pH4R-`E7b`DY zxzX!HwZeO{WNS*dcPT}ITK6qFIJmC8pj8<{8~Y(KxAIzby=ZD|-Zq5aBGac$HSXo- zJ+=+$u(zv&d%XgJMw<6NrtZ-Kc#DaL0@lSGq|xftPCNfCLVf-bM(9~wc}21^O9(s1 zc|~ByJ43VqXs9((FFa+uE2UVuLln?*L|F%5gWuQtAlyevdlWroFRf&;Wi7MSl76QX@;!aHD=Mei8iDud=4hpofFUSV>Ol zgBir4g|fx1YDalB;1rQJF;pdCL<907{6)}41EB(`<^n6)v9+nxpxvan0;lYk5uBW6h{loHsGd(_P;;H>aA)Go8y*Fm#XCX-A2fP7^Kb5&GYq@`?&i+q+d@;f@h9 z;6$0lb>sZTU<0<1Qe%yV= z;dZ}TbW&0p7cU3eH>Di)j(Kzu5q&rXY-9et+%3BT6?svBoZutze$(BWLbm?EX9gN` zU|QNSa#?Xn%+>fTQsohYs*{=QGp0M4g^v+g;WJSML93vFRs=D2pual7%!XDJ$tYtLVAfOReSk*7W6yG1Nq7QV@?~(RCev+!+`< zXv#+G88+B=qx~0Uf}|U?T1DK$mw<_VTNeMrtk>@aYFXLD7FE5A) z^XKh=qR6w0$xoC9l=94zeQZL<6o5E9Wkr|+Z!cxcMu=$6X@IGjV|j&kA*yHxfm2Tu}OUB}gb}rnY6@N?%`p z!YVjhyT~=jdP`<(vt3Hut*LBaoWZnAsqg`sh{*CBfMiQdmXl*HMn*@f1Lgd4o(HXX81Ng28r*ylOQi}eS_i=ll<8ws zAFIhH?RXyT#W&kRSj!AFo3`H0)-p}F)yN=PQA!1D92?Sz)-Ww!#M5nCD#+QAp+*K^ zv_F1~CffRAC>=;;{sl6G0x6CMJkJpi#WM_2%*fp}&+;yPBz1OEe{;8c~AeW)6 zL8^1UTmb)7!<}ZY3K4+iB7`L^h^UrQG&@9}AAC+K>*c-6n+&GVMBPXJYVXZQKx+>v zS4YUOtr&Fa4oT^+A()E^u*?iby!)j@X>;?y1$1`Us*1?F(j4ezf&Y;0* z=0&DECDF?uIUo*OL(EhaK-YidHS5C>I$q8RSffpCJA5KuqUQN%&4Q3x+zaTal)qn` zCz#|>ZBXc2U)2(N<%y0S;|$d*&;;mZV~}o zp=1WRBdRNLQG*T$$=83xk|Dud-#f`ed#sW@?;S4?#ftnpI{oi{0l33IvhcAlp|30& zD1h7U7<|jh*MS^|0G}Vii2jj>M0%{27T0Q)FafvP6Vh&HUKXKZx@H0N;;tux_2Sg@ zc+W!1+71E#H3x2Jrv*(3zE`YMST875Gl(vrmj;;2mWx0Fu1wSok8z8fP<;aAwcE^) zGoH2_`4?!X$ZC=}uLAiEvfy7<#HdWx<(Zttta3I#O{mTqM8I)nrv(Om4+?w(zdUUrK6b?~4UZ3~p z7g%gI>qI`GKJThs*oKU@-k5;)>K9DJVmj7Qn@PHiL=T6~0ZmBLZtkD&(Cxii+wR9k zslY~+a-aV^T+0_N#9$v_dxpEg{-u`iMZGu^0}`TZJ;0l@@zE*PFZ-5ciL!!-V{h#1 zU7qMyQ3zTHB%fYZ8ESa@&>-Jm^h3&NqIb|I(A)8^Y^i4R(7C?D;YIdp6o&LFa*pO< z8NL%48LI60q2vln^s`8-k+G2)&Qf6@mXZSdJ*%$7N0$w~a^EA;y;$YAv+ONVcixlHU!&jeZ~GDLW9j}e=--YX z4704G%k>3@%6J65P4*k-JOE1hE@(8NtkhFgBL)c8ng>&qiWP=%6#?&8OiE>d1v(NA zIT$pw4z}=?8ja^bm!ismep`VB-B~(1O^}=xK(e3xi(T2!^#b&bBJjfh`Zclds$rBG z%wTR#S0cNXhdd=^$^!vM*Sad{MfFU3YX@gH8I@QT(g)}(ZUv+tE>t>+2Mxg2_a}6N z*F6jAXClQHM&FC6;l+fpW~E~o6z}v7LmY^m=wTAkUuXAV@-J)Vq#gko-#@HM_Wn{k z7gsjzp^x%jouDg*D1_Nd;UN^eW{T^Lm@cX@l(YS&gqLfO`}q2r1U?|$xuAFMhTejc zDFcNF(Zeku$NcF*Z_h|MhS|1D{Rv=He*&1u_)An-X*fDZ<2p8`xHoL1l79>pgx2zp z7!CRMq6Tx|R*$1qEiJs~fes~55=j$1^Z=sBe+_FZbqDdP#OsqQAJarGrWHiHQ>7PG zED_!BJORJ>Y-PSGpW^A>94@c1ZT&_?t}H{G@A6kGsl9gK#ACGq`-G*${yG`dDU__3 zzP0#}<3&ZO-CS+dGE(I}sj6x7O=uiGBzUwd>IdZe~NZ)JMFsm7UoL=`^y z`jl$TT#-w4Jo+5b6>CB`NsBcaHh>6^kf}N_vapzy(D|*>pgg*c8r|AeqlJj@t=3k9 z@aRVXUdc1~fmc*(HsjC3K@)BZ^edfZN|K2|n(7+EWHE-P?!0&m_#KEEbm1OtM+D8_ zA4I!=LTO&-tz(*w)Uyv-LL6*h1vVBSTwVI#N;FalMn-f;^jp>w5JCEM<)1_LBgWj5 zMz^0BMwCE$@Y1ZG0X*;F?9Ua#%oKYH6O$==C=8uv8@Zx?b=jq2AyRBULI7T71ng`d zoQM7qaG2C<72t-2dV;DA!WV^yi9tMNF+hl|KJ(YJ4VRoBS}jm6n}Ru>2WE04{;Q=D z`y&6h4&gswS2`N8iVothw=awP*s|{$zVX&*D;wn)%Xo_D1>`RQktt?Imus}(p5&^U zW>{*X7+dY>_#ch{ed60gfb)1W$`le~w+h2icvGl`Zb*y$Ms|X#7=4DG+JwtQ1lFQD zs|fo%wVIXnG|`ouzmBXvymh#MM@IO4M5DB<7xL-TwVLns)Fc_r>VUW-c zkl|mp*XNC|nmjh9h->$`TKk{@G(NWA(=#fc!`kMp>c~vaQp4kwB#jV62)RrVMmA9! zC)!wKJ*|eDXPz6PG4FCc{nNb&;opfD=;9Eg4jShaNN(WzXM9GtTHy^35)-`_x32#L z@7uE*Tum=UdBlg4?$306+L^!V)pv(MsWn5$NT6Ps>l$D_RKV(DO8^@o5+(X+eH8c4 z6I4?F7`uVn|3nzo`~;yNQU0S%fNTOj#PYOyQAI-$W&nk@oIo=3nZn4oRN$; z2bk>gU5(42&B&+4bc-5&C_28qAyC{PXZUQuEe*>G(`la8C0@`_pcC+uF3fuKinbx|b zuT8g@|3%l*-Jd13Fqo@Qx^o$pTB=&esJaJ~)Am_M+}*d;V~6*CufpX&ib1NQeZT3B zxs*Ta7!euQn%PiRG5~-W-L8p+QB==frJiZtstzuCqHp*e9sdZ zqqK9zaMx4=@2`i{0t2<1sGT05#CMxDI|$mDhyyfbL_{*Nsv;m=gPXPPGlC-aAD=~0 za!m|fX5s)CP{%j7z{3>NDo@zZD}1DOFXgg)`+f3Rw?Y9i1l^+`PXHv*r!<9-lLC%4 z*#7))Ew~|{lq&na%6zsTOpZq1rSt1A_46-p?P}CKC2K9IaxauN?25bJvFGzTnnA+J zH?%B^re~@ZpbdVQ6nzvF@h9s~cjd}6YCfaSdtiPenNx|S&n-+lk++kBU(_uY-8d#| zc~j+n&647#xGYCL_^V|T1$6?n+Viym&VNSX*EaSkK@60PUYl`HkH~KP=3e+sD?8kF zwx(*Mlw~Vtm?-=v4A)23M^zf|Lsn>*v1^w*ZOV<+wLahbcb&iZhcpRNbW_E~hd)2k zJ$Mjf*ej`MgQ2l#8n2Nja6dn-pB)^1lzo|+BCE*5uCZd-FWPnhkneH)HXscM6?MX^ z2RG%m2xM?|_^+1*I0Jw(`SUg)*>nxE6KLiFF2L!!2A74d0>*HIex26fs#3H|4)7(= zT4(Lx7}W-;H5i1dS4%YiGBa9P98A=+znK{Bq{x6k;1Akxt^=d!X{L7&Dz`{3g zatC2IG*ebuQ;+P(AZN_ve;>qu7x9fF!Vm&}cDJBNRShv-)l#afW#=#~<%R_o1dO?M z=C_@)fpm#=XHEXbN}IatfVz7wfQPAn=+Q`-cLEVQG>mixV@PGDj z@3W^s*M~tVbEO%c!TcQH#TTBYdG`fO5PDvFeZD~VEu^|NJ5%|8;l9+iiUpk1Y}8u9 z_o>+^8r?dgR9*|R8r?`doDS6+IIi9X^{R>SGV1=`hkx`}YFkK06vS7SCZ;kzc%Q_~ zH9(p^@lHp9*)0N=!4 zp4_4>*UFYQr4h2?KYjXi<-N{}O;+KZWtN(m`XXjr94sEVp20vE1gJv^dgdg1fY|!g zl?DfWUsL^;wlrUNG_*~neekQk_AP1Ho5zWaBR*{KR)h&P;W%grNBIA`JN+Py0|EJq z_oW}gk`|y>O~|W&#ARCRe{dv1QZD|VbE(6wVu2CNvy`1c3aW|eI1~&zrx4QV6H34f ze>@C>mV}o)cxBmSlqzKH_M7B;C0+u^J8YBxoxDTt!I}^=Atbc`4B^)zYZ^fdZv7$+ zm|bsb_r_F{-QMb$aL{*`baD4=K>DIj#w3|6>F%v)`%3Bo#CG(j>ILm|1DrP^gu~&4 z9r_v5CA^CGP2Rk_h$LtYRHB#%;M8;rAVPxe6`YUU79{mtp*IF7Wamh?$z!2KfyF%0)C1l*8elZmd_84 z$iN)0GTFY#uVS)qse&s_-2Eh_iuO=8ta>e<1fnvRrOB$-f1TcclN($l;zF_rSeA5lRbz3aSgzG}U!o)>_LIaa7k&XV8 zQ|io@{oMb*cHw^})IRtVbQ#ouE~9znQ7+jhK$kK1k)X?%Z+;h=FWCp2iRVY3C+mS- z`U|eL=$;*3UhVHBR@#VApqCN>XSw~S8Scjza%pGt$IuF;K6>;^**6U9EZbX&uiqKL z*+L2g**AnX%{XKV^OjZu$;A~#sz0&w33@chwtTHg8r8H^-z*&;jRh7{$So!hx|vNc zhm@|fJ!JQ`3ML<4N|BaD*=y8Fj|=(B;11i?A7e1S=YBd`*8d!uY>v04G7OUTSR*Rq z{}@eha#$%k>lvd_qo5(_YHTlQKH}8)UxEy_nk?r(1sN_}mNiVZ3^*i90$RP_Z(!U) zoZhSpBrUYt936hud}IB*HLwe_zHOL{pCpz$puFSW2$DBY@y_@Fq|3Y+ox>i>fL|IH5_{!%~4{e%!C|E9_LA(_@X_(xCbp+{GdU?8$+`Ya)0dqm9) z<*X&>oS)(&WSVP&TT+KfIMC|Lpr=bYVa$YEwjyVS99YDq{ht`58r!y=C7EYq!9gvW z=kFb?W?83@YP)~CA2-#$`8dF!L2 zCq9jj=DHHt2vgy|Nd;o-XCE=l7fBiSW})3u_L_`)G>?SRoU={1%bCsj$6SrO`xp?c zsL8kYK0fX6>Cwiw%Od-=gXOo=8Bh7ynlctHa4ij_T%w_>qw*x?%vn^9`mbP(??JeuZW`79>4 zDD#~&eP?baZ5$n{J^gk;eBl*-#P-Wzf?elCMSw#*zTKw>+lt@Y-Y>qzq0Mi`eqOKv z@;z)jX?spP%nWZg_o1MFgw~RMAb2Zg`xOZ0a0~Atf%gmJ!shs9tTk_aD9{r3*#CBy z0PsGrger&OPNRB@jy6)=nGPzC*Egbs-Md(NCRq?e7mz%jA3_j(`my03$GtOLr0bOg zTQ=Pb0#7^-w#5DZw1!J%~ zn@cF=SF)>SFDde*Tv@*%DnnL>8jw0l|-+S!*rF^~!-nX45e{f^|jR@Y__EWeEe zJ2lOPMLa0~II~qOjGYzlNe6b(ej1Aw-U~X>#2;^ld+Au`V8QtJuMb5P~OT{c$jkgt@U z9WLa@3)Vd%i=Rc5^bBriA2cD7g7CZA3nWDw3C8f`Ffz@)-7GF+hJ*TrO7C$$98R~e z0eXpy4E)3H9%MBOYFPTY8wv({$2Z%cH+y1_thn@Bv6-HSQx&OoGg}uW_CBQ{#bgf? zk%(xElXs|jVEVhK62l*QGB|L(rvPu1K(6!Q^*gs`)7u-a&OfdY=Vx(F?>D`E9oR4<0c-7gNv9kTH+X4lI*Cz#s&*@$ZF@FzZ8( zgAIlmM~?Yf=L!Ly?pzG$jW_{*yNIsn#ke2Z1+4f0zio@2c{b6X z!6+H5gWq2j??p7cVwd$(RK@qDsc(O%IDTvqrfxq}7OkQqcnqVUh8<48CXuRbY@>3r zL73N-L5ms^yDyblY@KNtPCAQf*^uUabxR=y8 zqyM{9%)G+@PJ?C&Pt0R!mKf%zsT%6^^x&W-@x{Gb_X|-ffdb0eAM z2?f#dtYiSLva({v7?$9c;Xs>@|1v1!+0!GAAo;eE$R;rLB$V;J|&8T0E(9%aXQXpGWdpU1w)KnUzJhp_)Ia zA>(t7Bo1J+v-;X8me%|78$n7Dj+IL69Moo5h$1_?3~+`(L;ue+oOvENvgkZdi!ezH zJ03DLQmSQ|s}N2}6~Duzbi36!5rr>d7YY4FKi<5j)!?gs z8?p;KV215pP&I?Nbc+>Pou>21+OCSB>4q7%3UjcUb7>~pIb?B|!|UaJLpHp&2U(6E zxd>Burrm9sZLMooJSW&{lFdg?_cn1>Go2ly)T~%s{4v?wj1HvwJ#vCX$VjaErkK}e z3-)I;`X+T)jZTiMNLt;=*5*t0OU?dWqtQ2GEXQNk?oX`T$4aH<>{Ezb@pvN(F1(49S2o+LR12@8|`>1>F6KXTl}cl>5L z;(b`N6&~N8(0$VAlX%?Oi0b9YoaU>;`8P}+wKpv!a-_wUhA#t2_|SSt<~XGSNx2!2 zFzNq&eEZAxLYuor4I5j|Ve;fjS{RS@(Xz5#1?V{~VkgU@#qEpW&X4-`ir+p{OVDzd zloFyAH$jT((VVdosB<;pt9yNvI@yS)S!t@$HVSoLcn(O^$PqT566QDXi{cAIn2I#o zjb;&_k4yWFK9yt89yo*hni;X~4VTXkfxh3n{r1ge?eEGZPd2FC5IEmIGkm42Jd=0D zx7Y3=B){|IFT6DwywgWG0HRo#0qLFC=KZfR0iYq^_tii%I7&@L4F~}MO2`)PJvsl1 Wxo56K@2G - only for conversion ''' Public FieldsChecker As Boolean = False + ''' Interaction with changing text field. Default: + Public Interaction As Boolean = False ''' Initialize a new Provider attribute. is only allowed ''' The name of the property for which this provider is used Public Sub New(ByVal PropertyName As String) diff --git a/SCrawler.PluginProvider/Interfaces/IPropertyProvider.vb b/SCrawler.PluginProvider/Interfaces/IPropertyProvider.vb new file mode 100644 index 0000000..85508bb --- /dev/null +++ b/SCrawler.PluginProvider/Interfaces/IPropertyProvider.vb @@ -0,0 +1,13 @@ +' Copyright (C) 2023 Andy https://github.com/AAndyProgram +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Namespace Plugin + Public Interface IPropertyProvider : Inherits IFormatProvider + Property PropertyName As String + End Interface +End Namespace \ No newline at end of file diff --git a/SCrawler.PluginProvider/My Project/AssemblyInfo.vb b/SCrawler.PluginProvider/My Project/AssemblyInfo.vb index b9fd8cd..5ad7254 100644 --- a/SCrawler.PluginProvider/My Project/AssemblyInfo.vb +++ b/SCrawler.PluginProvider/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler.PluginProvider/SCrawler.PluginProvider.vbproj b/SCrawler.PluginProvider/SCrawler.PluginProvider.vbproj index 3bd708f..c5a6ecd 100644 --- a/SCrawler.PluginProvider/SCrawler.PluginProvider.vbproj +++ b/SCrawler.PluginProvider/SCrawler.PluginProvider.vbproj @@ -102,6 +102,7 @@ + diff --git a/SCrawler/API/Base/UserDataBase.vb b/SCrawler/API/Base/UserDataBase.vb index d833c12..5693be4 100644 --- a/SCrawler/API/Base/UserDataBase.vb +++ b/SCrawler/API/Base/UserDataBase.vb @@ -1023,12 +1023,14 @@ BlockNullPicture: End If If Not v.SpecialFolder.IsEmptyString Then - f.Path = $"{f.PathWithSeparator}{v.SpecialFolder}\".CSFileP.Path + f.Path = $"{f.PathWithSeparator}{v.SpecialFolder.StringTrimEnd("*")}\".CSFileP.Path f.Exists(SFO.Path) End If If __isVideo And vsf Then - f.Path = $"{f.PathWithSeparator}Video" - If Not v.SpecialFolder.IsEmptyString Then f.Exists(SFO.Path) + If v.SpecialFolder.IsEmptyString OrElse Not v.SpecialFolder.EndsWith("*") Then + f.Path = $"{f.PathWithSeparator}Video" + If Not v.SpecialFolder.IsEmptyString Then f.Exists(SFO.Path) + End If End If If v.Type = UTypes.m3u8 And UseInternalM3U8Function Then diff --git a/SCrawler/API/Instagram/UserData.vb b/SCrawler/API/Instagram/UserData.vb index c16c2e0..4f49608 100644 --- a/SCrawler/API/Instagram/UserData.vb +++ b/SCrawler/API/Instagram/UserData.vb @@ -613,17 +613,20 @@ Namespace API.Instagram With nn PostIDKV = New PostKV(.Value("code"), .Value("id"), Section) Pinned = .Contains("timeline_pinned_user_ids") - If PostKvExists(PostIDKV) And Not Pinned Then Return False - _TempPostsList.Add(PostIDKV.ID) - PostsKVIDs.ListAddValue(PostIDKV, LAP.NotContainsOnly) - PostDate = .Value("taken_at") - If Not IsSavedPosts Then - Select Case CheckDatesLimit(PostDate, DateProvider) - Case DateResult.Skip : Continue For - Case DateResult.Exit : If Not Pinned Then Return False - End Select + If PostKvExists(PostIDKV) Then + If Not Pinned Then Return False + Else + _TempPostsList.Add(PostIDKV.ID) + PostsKVIDs.ListAddValue(PostIDKV, LNC) + PostDate = .Value("taken_at") + If Not IsSavedPosts Then + Select Case CheckDatesLimit(PostDate, DateProvider) + Case DateResult.Skip : Continue For + Case DateResult.Exit : If Not Pinned Then Return False + End Select + End If + ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate) End If - ObtainMedia(.Self, PostIDKV.ID, SpecFolder, PostDate) End With Next Return True diff --git a/SCrawler/API/Twitter/Declarations.vb b/SCrawler/API/Twitter/Declarations.vb index a1a055c..1073ac4 100644 --- a/SCrawler/API/Twitter/Declarations.vb +++ b/SCrawler/API/Twitter/Declarations.vb @@ -12,6 +12,7 @@ Imports PersonalUtilities.Functions.RegularExpressions Namespace API.Twitter Friend Module Declarations Friend Const TwitterSite As String = "Twitter" + Friend Const TwitterSiteKey As String = "AndyProgram_Twitter" Friend ReadOnly DateProvider As ADateTime = GetDateProvider() Friend ReadOnly VideoNode As NodeParams() = {New NodeParams("video_info", True, True, True, True, 10)} Friend ReadOnly VideoSizeRegEx As RParams = RParams.DMS("\d+x(\d+)", 1, EDP.ReturnValue) diff --git a/SCrawler/API/Twitter/EditorExchangeOptions.vb b/SCrawler/API/Twitter/EditorExchangeOptions.vb new file mode 100644 index 0000000..dddbf05 --- /dev/null +++ b/SCrawler/API/Twitter/EditorExchangeOptions.vb @@ -0,0 +1,27 @@ +' Copyright (C) 2023 Andy https://github.com/AAndyProgram +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Namespace API.Twitter + Friend Class EditorExchangeOptions + Friend Property GifsDownload As Boolean + Friend Property GifsSpecialFolder As String + Friend Property GifsPrefix As String + Friend Sub New() + End Sub + Friend Sub New(ByVal s As SiteSettings) + GifsDownload = s.GifsDownload.Value + GifsSpecialFolder = s.GifsSpecialFolder.Value + GifsPrefix = s.GifsPrefix.Value + End Sub + Friend Sub New(ByVal u As UserData) + GifsDownload = u.GifsDownload + GifsSpecialFolder = u.GifsSpecialFolder + GifsPrefix = u.GifsPrefix + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/API/Twitter/OptionsForm.Designer.vb b/SCrawler/API/Twitter/OptionsForm.Designer.vb new file mode 100644 index 0000000..3330cfa --- /dev/null +++ b/SCrawler/API/Twitter/OptionsForm.Designer.vb @@ -0,0 +1,148 @@ +' Copyright (C) 2023 Andy https://github.com/AAndyProgram +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Namespace API.Twitter + + Partial Friend Class OptionsForm : Inherits System.Windows.Forms.Form + + Protected Overrides Sub Dispose(ByVal disposing As Boolean) + Try + If disposing AndAlso components IsNot Nothing Then + components.Dispose() + End If + Finally + MyBase.Dispose(disposing) + End Try + End Sub + Private components As System.ComponentModel.IContainer + + Private Sub InitializeComponent() + Dim CONTAINER_MAIN As System.Windows.Forms.ToolStripContainer + Dim TP_MAIN As System.Windows.Forms.TableLayoutPanel + Dim ActionButton1 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(OptionsForm)) + Dim ActionButton2 As PersonalUtilities.Forms.Controls.Base.ActionButton = New PersonalUtilities.Forms.Controls.Base.ActionButton() + Me.CH_DOWN_GIFS = New System.Windows.Forms.CheckBox() + Me.TXT_GIF_FOLDER = New PersonalUtilities.Forms.Controls.TextBoxExtended() + Me.TXT_GIF_PREFIX = New PersonalUtilities.Forms.Controls.TextBoxExtended() + CONTAINER_MAIN = New System.Windows.Forms.ToolStripContainer() + TP_MAIN = New System.Windows.Forms.TableLayoutPanel() + CONTAINER_MAIN.ContentPanel.SuspendLayout() + CONTAINER_MAIN.SuspendLayout() + TP_MAIN.SuspendLayout() + CType(Me.TXT_GIF_FOLDER, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.TXT_GIF_PREFIX, System.ComponentModel.ISupportInitialize).BeginInit() + Me.SuspendLayout() + ' + 'CONTAINER_MAIN + ' + ' + 'CONTAINER_MAIN.ContentPanel + ' + CONTAINER_MAIN.ContentPanel.Controls.Add(TP_MAIN) + CONTAINER_MAIN.ContentPanel.Size = New System.Drawing.Size(304, 84) + CONTAINER_MAIN.Dock = System.Windows.Forms.DockStyle.Fill + CONTAINER_MAIN.LeftToolStripPanelVisible = False + CONTAINER_MAIN.Location = New System.Drawing.Point(0, 0) + CONTAINER_MAIN.Name = "CONTAINER_MAIN" + CONTAINER_MAIN.RightToolStripPanelVisible = False + CONTAINER_MAIN.Size = New System.Drawing.Size(304, 109) + CONTAINER_MAIN.TabIndex = 0 + CONTAINER_MAIN.TopToolStripPanelVisible = False + ' + 'TP_MAIN + ' + TP_MAIN.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.[Single] + TP_MAIN.ColumnCount = 1 + TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_MAIN.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20.0!)) + TP_MAIN.Controls.Add(Me.CH_DOWN_GIFS, 0, 0) + TP_MAIN.Controls.Add(Me.TXT_GIF_FOLDER, 0, 1) + TP_MAIN.Controls.Add(Me.TXT_GIF_PREFIX, 0, 2) + TP_MAIN.Dock = System.Windows.Forms.DockStyle.Fill + TP_MAIN.Location = New System.Drawing.Point(0, 0) + TP_MAIN.Name = "TP_MAIN" + TP_MAIN.RowCount = 4 + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 28.0!)) + TP_MAIN.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!)) + TP_MAIN.Size = New System.Drawing.Size(304, 84) + TP_MAIN.TabIndex = 0 + ' + 'CH_DOWN_GIFS + ' + Me.CH_DOWN_GIFS.AutoSize = True + Me.CH_DOWN_GIFS.Dock = System.Windows.Forms.DockStyle.Fill + Me.CH_DOWN_GIFS.Location = New System.Drawing.Point(4, 4) + Me.CH_DOWN_GIFS.Name = "CH_DOWN_GIFS" + Me.CH_DOWN_GIFS.Padding = New System.Windows.Forms.Padding(100, 0, 0, 0) + Me.CH_DOWN_GIFS.Size = New System.Drawing.Size(296, 19) + Me.CH_DOWN_GIFS.TabIndex = 0 + Me.CH_DOWN_GIFS.Text = "Download GIFs" + Me.CH_DOWN_GIFS.UseVisualStyleBackColor = True + ' + 'TXT_GIF_FOLDER + ' + ActionButton1.BackgroundImage = CType(resources.GetObject("ActionButton1.BackgroundImage"), System.Drawing.Image) + ActionButton1.Name = "Clear" + ActionButton1.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_GIF_FOLDER.Buttons.Add(ActionButton1) + Me.TXT_GIF_FOLDER.CaptionText = "GIFs special folder" + Me.TXT_GIF_FOLDER.CaptionToolTipText = "Put the GIFs in a special folder" + Me.TXT_GIF_FOLDER.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_GIF_FOLDER.Location = New System.Drawing.Point(4, 30) + Me.TXT_GIF_FOLDER.Name = "TXT_GIF_FOLDER" + Me.TXT_GIF_FOLDER.Size = New System.Drawing.Size(296, 22) + Me.TXT_GIF_FOLDER.TabIndex = 1 + ' + 'TXT_GIF_PREFIX + ' + ActionButton2.BackgroundImage = CType(resources.GetObject("ActionButton2.BackgroundImage"), System.Drawing.Image) + ActionButton2.Name = "Clear" + ActionButton2.Tag = PersonalUtilities.Forms.Controls.Base.ActionButton.DefaultButtons.Clear + Me.TXT_GIF_PREFIX.Buttons.Add(ActionButton2) + Me.TXT_GIF_PREFIX.CaptionText = "GIF prefix" + Me.TXT_GIF_PREFIX.CaptionToolTipText = "This prefix will be added to the beginning of the filename" + Me.TXT_GIF_PREFIX.Dock = System.Windows.Forms.DockStyle.Fill + Me.TXT_GIF_PREFIX.Location = New System.Drawing.Point(4, 59) + Me.TXT_GIF_PREFIX.Name = "TXT_GIF_PREFIX" + Me.TXT_GIF_PREFIX.Size = New System.Drawing.Size(296, 22) + Me.TXT_GIF_PREFIX.TabIndex = 2 + ' + 'OptionsForm + ' + Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) + Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font + Me.ClientSize = New System.Drawing.Size(304, 109) + Me.Controls.Add(CONTAINER_MAIN) + Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle + Me.Icon = Global.SCrawler.My.Resources.SiteResources.TwitterIcon_32 + Me.MaximizeBox = False + Me.MaximumSize = New System.Drawing.Size(320, 148) + Me.MinimizeBox = False + Me.MinimumSize = New System.Drawing.Size(320, 148) + Me.Name = "OptionsForm" + Me.ShowInTaskbar = False + Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide + Me.Text = "Options" + CONTAINER_MAIN.ContentPanel.ResumeLayout(False) + CONTAINER_MAIN.ResumeLayout(False) + CONTAINER_MAIN.PerformLayout() + TP_MAIN.ResumeLayout(False) + TP_MAIN.PerformLayout() + CType(Me.TXT_GIF_FOLDER, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.TXT_GIF_PREFIX, System.ComponentModel.ISupportInitialize).EndInit() + Me.ResumeLayout(False) + + End Sub + Private WithEvents CH_DOWN_GIFS As CheckBox + Private WithEvents TXT_GIF_FOLDER As PersonalUtilities.Forms.Controls.TextBoxExtended + Private WithEvents TXT_GIF_PREFIX As PersonalUtilities.Forms.Controls.TextBoxExtended + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/API/Twitter/OptionsForm.resx b/SCrawler/API/Twitter/OptionsForm.resx new file mode 100644 index 0000000..27f385b --- /dev/null +++ b/SCrawler/API/Twitter/OptionsForm.resx @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + False + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAIZJREFUOE+1j10KwCAMgz2b755xl/IsvnaL2K20UfbDAmEako+ZROSTafjE12Go + tbbB43rK5xSAQq1VYFtmeQBoqZTSreVZvgTknM8yyyjA/qodsDF9gspD2Bj6B+DH+NqzhQQAG+POMnSX + AFuc5QFgn6ClHh5iOQVAKNixyucB8NY0vG9JOzzyhrdq5IRgAAAAAElFTkSuQmCC + + + \ No newline at end of file diff --git a/SCrawler/API/Twitter/OptionsForm.vb b/SCrawler/API/Twitter/OptionsForm.vb new file mode 100644 index 0000000..e7f74be --- /dev/null +++ b/SCrawler/API/Twitter/OptionsForm.vb @@ -0,0 +1,78 @@ +' Copyright (C) 2023 Andy https://github.com/AAndyProgram +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY +Imports System.Reflection +Imports SCrawler.Plugin.Attributes +Imports PersonalUtilities.Forms +Imports PersonalUtilities.Forms.Controls +Namespace API.Twitter + Friend Class OptionsForm + Private WithEvents MyDefs As DefaultFormOptions + Private ReadOnly Property MyExchangeOptions As EditorExchangeOptions + Private ReadOnly MyGifTextProvider As SiteSettings.GifStringProvider + Friend Sub New(ByRef ExchangeOptions As EditorExchangeOptions) + InitializeComponent() + MyExchangeOptions = ExchangeOptions + MyGifTextProvider = New SiteSettings.GifStringProvider + MyDefs = New DefaultFormOptions(Me, Settings.Design) + End Sub + Private Sub OptionsForm_Load(sender As Object, e As EventArgs) Handles Me.Load + With MyDefs + .MyViewInitialize(True) + .AddOkCancelToolbar() + With MyExchangeOptions + CH_DOWN_GIFS.Checked = .GifsDownload + TXT_GIF_FOLDER.Text = .GifsSpecialFolder + TXT_GIF_FOLDER.Tag = NameOf(SiteSettings.GifsSpecialFolder) + TXT_GIF_PREFIX.Text = .GifsPrefix + TXT_GIF_PREFIX.Tag = NameOf(SiteSettings.GifsPrefix) + + Try + Dim p As PropertyOption + With Settings(TwitterSiteKey) + p = .PropList.Find(Function(pp) pp.Name = TXT_GIF_FOLDER.Tag).Options + If Not p Is Nothing Then + TXT_GIF_FOLDER.CaptionText = p.ControlText + TXT_GIF_FOLDER.CaptionToolTipText = p.ControlToolTip + TXT_GIF_FOLDER.CaptionToolTipEnabled = Not TXT_GIF_FOLDER.CaptionToolTipText.IsEmptyString + End If + + p = .PropList.Find(Function(pp) pp.Name = TXT_GIF_PREFIX.Tag).Options + If Not p Is Nothing Then + TXT_GIF_PREFIX.CaptionText = p.ControlText + TXT_GIF_PREFIX.CaptionToolTipText = p.ControlToolTip + TXT_GIF_PREFIX.CaptionToolTipEnabled = Not TXT_GIF_PREFIX.CaptionToolTipText.IsEmptyString + End If + End With + Catch + End Try + End With + .EndLoaderOperations() + End With + End Sub + Private Sub MyDefs_ButtonOkClick(ByVal Sender As Object, ByVal e As KeyHandleEventArgs) Handles MyDefs.ButtonOkClick + With MyExchangeOptions + .GifsDownload = CH_DOWN_GIFS.Checked + .GifsSpecialFolder = TXT_GIF_FOLDER.Text + .GifsPrefix = TXT_GIF_PREFIX.Text + End With + MyDefs.CloseForm() + End Sub + Private Sub TXT_ActionOnTextChanged(ByVal Sender As TextBoxExtended, ByVal e As EventArgs) Handles TXT_GIF_FOLDER.ActionOnTextChanged, + TXT_GIF_PREFIX.ActionOnTextChanged + If Not MyDefs.Initializing Then + With Sender + MyGifTextProvider.PropertyName = .Tag + Dim s% = .SelectionStart + Dim t$ = AConvert(Of String)(.Text, String.Empty, MyGifTextProvider) + If Not .Text = t Then .Text = t : .Select(s, 0) + End With + End If + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/SCrawler/API/Twitter/SiteSettings.vb b/SCrawler/API/Twitter/SiteSettings.vb index 66f2fb7..e34ca4b 100644 --- a/SCrawler/API/Twitter/SiteSettings.vb +++ b/SCrawler/API/Twitter/SiteSettings.vb @@ -13,10 +13,11 @@ Imports PersonalUtilities.Functions.RegularExpressions Imports PersonalUtilities.Tools.Web.Clients Imports PersonalUtilities.Tools.Web.Cookies Namespace API.Twitter - + Friend Class SiteSettings : Inherits SiteSettingsBase Friend Const Header_Authorization As String = "authorization" Friend Const Header_Token As String = "x-csrf-token" +#Region "Declarations" Friend Overrides ReadOnly Property Icon As Icon Get Return My.Resources.SiteResources.TwitterIcon_32 @@ -27,14 +28,50 @@ Namespace API.Twitter Return My.Resources.SiteResources.TwitterPic_400 End Get End Property - Private ReadOnly Property Auth As PropertyValue - + Private ReadOnly Property Token As PropertyValue - + Friend ReadOnly Property SavedPostsUserName As PropertyValue +#End Region +#Region "Other properties" + + Friend ReadOnly Property GifsDownload As PropertyValue + + Friend ReadOnly Property GifsSpecialFolder As PropertyValue + + Friend ReadOnly Property GifsPrefix As PropertyValue + + Private ReadOnly Property GifStringChecker As IFormatProvider + Friend Class GifStringProvider : Implements ICustomProvider, IPropertyProvider + Friend Property PropertyName As String Implements IPropertyProvider.PropertyName + Private Function Convert(ByVal Value As Object, ByVal DestinationType As Type, ByVal Provider As IFormatProvider, + Optional ByVal NothingArg As Object = Nothing, Optional ByVal e As ErrorsDescriber = Nothing) As Object Implements ICustomProvider.Convert + Dim v$ = AConvert(Of String)(Value, String.Empty) + If Not v.IsEmptyString Then + If PropertyName = NameOf(GifsPrefix) Then + v = v.StringRemoveWinForbiddenSymbols + Else + v = v.StringReplaceSymbols(GetWinForbiddenSymbols.ToList.ListWithRemove("\").ToArray, String.Empty, EDP.ReturnValue) + v = v.StringTrim("\") + End If + End If + Return v + End Function + Private Function GetFormat(ByVal FormatType As Type) As Object Implements IFormatProvider.GetFormat + Throw New NotImplementedException("[GetFormat] is not available in the context of [TimersChecker]") + End Function + End Class +#End Region Friend Overrides ReadOnly Property Responser As Responser +#End Region Friend Sub New() MyBase.New(TwitterSite) Responser = New Responser($"{SettingsFolderName}\Responser_{Site}.xml") @@ -72,6 +109,11 @@ Namespace API.Twitter Token = New PropertyValue(t, GetType(String), Sub(v) ChangeResponserFields(NameOf(Token), v)) SavedPostsUserName = New PropertyValue(String.Empty, GetType(String)) + GifsDownload = New PropertyValue(True) + GifsSpecialFolder = New PropertyValue(String.Empty, GetType(String)) + GifsPrefix = New PropertyValue("GIF_") + GifStringChecker = New GifStringProvider + UserRegex = RParams.DMS("[htps:/]{7,8}.*?twitter.com/([^/]+)", 1) UrlPatternUser = "https://twitter.com/{0}" ImageVideoContains = "twitter" @@ -106,5 +148,11 @@ Namespace API.Twitter Friend Overrides Function BaseAuthExists() As Boolean Return If(Responser.Cookies?.Count, 0) > 0 And ACheck(Token.Value) And ACheck(Auth.Value) End Function + Friend Overrides Sub UserOptions(ByRef Options As Object, ByVal OpenForm As Boolean) + If Options Is Nothing OrElse Not TypeOf Options Is EditorExchangeOptions Then Options = New EditorExchangeOptions(Me) + If OpenForm Then + Using f As New OptionsForm(Options) : f.ShowDialog() : End Using + End If + End Sub End Class End Namespace \ No newline at end of file diff --git a/SCrawler/API/Twitter/UserData.vb b/SCrawler/API/Twitter/UserData.vb index f23319f..392ae7a 100644 --- a/SCrawler/API/Twitter/UserData.vb +++ b/SCrawler/API/Twitter/UserData.vb @@ -17,15 +17,50 @@ Imports UStates = SCrawler.API.Base.UserMedia.States Namespace API.Twitter Friend Class UserData : Inherits UserDataBase Private Const SinglePostUrl As String = "https://api.twitter.com/1.1/statuses/show.json?id={0}&tweet_mode=extended" +#Region "XML names" + Private Const Name_GifsDownload As String = "GifsDownload" + Private Const Name_GifsSpecialFolder As String = "GifsSpecialFolder" + Private Const Name_GifsPrefix As String = "GifsPrefix" +#End Region #Region "Declarations" + Friend Property GifsDownload As Boolean + Friend Property GifsSpecialFolder As String + Friend Property GifsPrefix As String Private ReadOnly _DataNames As List(Of String) - Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean) +#End Region +#Region "Exchange options" + Friend Overrides Function ExchangeOptionsGet() As Object + Return New EditorExchangeOptions(Me) + End Function + Friend Overrides Sub ExchangeOptionsSet(ByVal Obj As Object) + If Not Obj Is Nothing AndAlso TypeOf Obj Is EditorExchangeOptions Then + With DirectCast(Obj, EditorExchangeOptions) + GifsDownload = .GifsDownload + GifsSpecialFolder = .GifsSpecialFolder + GifsPrefix = .GifsPrefix + End With + End If End Sub #End Region -#Region "Initializer" +#Region "Initializer, loader" Friend Sub New() _DataNames = New List(Of String) End Sub + Protected Overrides Sub LoadUserInformation_OptionalFields(ByRef Container As XmlFile, ByVal Loading As Boolean) + If Loading Then + GifsDownload = Container.Value(Name_GifsDownload).FromXML(Of Boolean)(True) + GifsSpecialFolder = Container.Value(Name_GifsSpecialFolder) + If Not Container.Contains(Name_GifsPrefix) Then + GifsPrefix = "GIF_" + Else + GifsPrefix = Container.Value(Name_GifsPrefix) + End If + Else + Container.Add(Name_GifsDownload, GifsDownload.BoolToInteger) + Container.Add(Name_GifsSpecialFolder, GifsSpecialFolder) + Container.Add(Name_GifsPrefix, GifsPrefix) + End If + End Sub #End Region #Region "Download functions" Protected Overrides Sub DownloadDataF(ByVal Token As CancellationToken) @@ -182,10 +217,11 @@ Namespace API.Twitter url = .Value("url") ff = UrlFile(url) If Not ff.IsEmptyString Then - If Not _DataNames.Contains(ff) Then + If GifsDownload And Not _DataNames.Contains(ff) Then m = MediaFromData(url, PostID, PostDate,, State) f = m.File - If Not f.IsEmptyString Then f.Name = $"GIF_{f.Name}" : m.File = f + If Not f.IsEmptyString And Not GifsPrefix.IsEmptyString Then f.Name = $"{GifsPrefix}{f.Name}" : m.File = f + If Not GifsSpecialFolder.IsEmptyString Then m.SpecialFolder = $"{GifsSpecialFolder}*" _TempMediaList.ListAddValue(m, LNC) End If Return True diff --git a/SCrawler/Editors/UserCreatorForm.vb b/SCrawler/Editors/UserCreatorForm.vb index 6260ae8..ae0d63a 100644 --- a/SCrawler/Editors/UserCreatorForm.vb +++ b/SCrawler/Editors/UserCreatorForm.vb @@ -397,6 +397,7 @@ CloseForm: CMB_SITE.SelectedIndex = -1 CMB_SITE.Clear(ComboBoxExtended.ClearMode.Text) CH_IS_CHANNEL.Checked = False + If Not UserIsCollection Then Icon = My.Resources.UsersIcon_32 End If End If _TextChangeInvoked = False @@ -412,6 +413,9 @@ CloseForm: MyExchangeOptions = Nothing SetParamsBySite() End Sub + Private Sub CMB_SITE_ActionOnTextChanged(sender As Object, e As EventArgs) Handles CMB_SITE.ActionOnTextChanged + If CMB_SITE.Text.IsEmptyString And Not UserIsCollection Then CMB_SITE.SelectedIndex = -1 : Icon = My.Resources.UsersIcon_32 + End Sub Private Sub BTT_OTHER_SETTINGS_Click(sender As Object, e As EventArgs) Handles BTT_OTHER_SETTINGS.Click Dim s As SettingsHost = GetSiteByCheckers() If Not s Is Nothing Then @@ -604,9 +608,17 @@ CloseForm: Else BTT_OTHER_SETTINGS.Enabled = False End If + If Not UserIsCollection Then + If Not s.Source.Icon Is Nothing Then + Icon = s.Source.Icon + ElseIf Not s.Source.Image Is Nothing Then + Icon = ImageRenderer.GetIcon(s.Source.Image, New ErrorsDescriber(False, False, False, My.Resources.UsersIcon_32)) + End If + End If End With Else BTT_OTHER_SETTINGS.Enabled = False + If Not UserIsCollection Then Icon = My.Resources.UsersIcon_32 End If End Sub Private Sub ChangeLabels() diff --git a/SCrawler/My Project/AssemblyInfo.vb b/SCrawler/My Project/AssemblyInfo.vb index c020c8e..43195ea 100644 --- a/SCrawler/My Project/AssemblyInfo.vb +++ b/SCrawler/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - - + + diff --git a/SCrawler/PluginsEnvironment/Hosts/PropertyValueHost.vb b/SCrawler/PluginsEnvironment/Hosts/PropertyValueHost.vb index d4393c4..0fc4edc 100644 --- a/SCrawler/PluginsEnvironment/Hosts/PropertyValueHost.vb +++ b/SCrawler/PluginsEnvironment/Hosts/PropertyValueHost.vb @@ -76,6 +76,7 @@ Namespace Plugin.Hosts .EndInit(True) End With AddHandler .ActionOnButtonClick, AddressOf TextBoxClick + If Not ProviderValue Is Nothing AndAlso ProviderValueInteraction Then AddHandler .ActionOnTextChanged, AddressOf TextBoxTextChanged End With End If End If @@ -98,6 +99,14 @@ Namespace Plugin.Hosts ErrorsDescriber.Execute(EDP.LogMessageValue, ex, $"Updating [{Name}] property") End Try End Sub + Private Sub TextBoxTextChanged(ByVal Sender As Object, ByVal e As EventArgs) + UpdateProviderPropertyName() + With DirectCast(Sender, TextBoxExtended) + Dim s% = .SelectionStart + Dim t$ = AConvert(Of String)(.Text, ProviderValue, String.Empty) + If Not t = .Text Then .Text = t : .Select(s, 0) + End With + End Sub Friend Sub UpdateValueByControl() If Not Control Is Nothing AndAlso Not TypeOf Control Is Label Then If TypeOf Control Is CheckBox Then @@ -105,6 +114,7 @@ Namespace Plugin.Hosts If Options.ThreeStates Then Value = CInt(.CheckState) Else Value = .Checked End With Else + UpdateProviderPropertyName() Value = AConvert(DirectCast(Control, TextBoxExtended).Text, AModes.Var, [Type],,,, ProviderValue) End If End If @@ -116,12 +126,16 @@ Namespace Plugin.Hosts If Options.ThreeStates Then Return CInt(.CheckState) Else Return .Checked End With Else + UpdateProviderPropertyName() Return AConvert(DirectCast(Control, TextBoxExtended).Text, AModes.Var, [Type],,,, ProviderValue) End If Else Return Nothing End If End Function + Private Sub UpdateProviderPropertyName() + If ProviderValueIsPropertyProvider Then DirectCast(ProviderValue, IPropertyProvider).PropertyName = Name + End Sub #End Region #Region "Compatibility" Private ReadOnly Source As Object @@ -143,9 +157,17 @@ Namespace Plugin.Hosts End Property #Region "Providers" Friend Property ProviderFieldsChecker As IFormatProvider - Friend Property ProviderValue As IFormatProvider - Friend Sub SetProvider(ByVal Provider As IFormatProvider, ByVal FC As Boolean) - If FC Then ProviderFieldsChecker = Provider Else ProviderValue = Provider + Private Property ProviderValue As IFormatProvider + Private Property ProviderValueInteraction As Boolean = False + Private Property ProviderValueIsPropertyProvider As Boolean = False + Friend Sub SetProvider(ByVal Provider As IFormatProvider, ByVal Instance As Provider) + If Instance.FieldsChecker Then + ProviderFieldsChecker = Provider + Else + ProviderValue = Provider + ProviderValueIsPropertyProvider = TypeOf ProviderValue Is IPropertyProvider + ProviderValueInteraction = Instance.Interaction + End If End Sub #End Region Friend PropertiesChecking As String() diff --git a/SCrawler/PluginsEnvironment/Hosts/SettingsHost.vb b/SCrawler/PluginsEnvironment/Hosts/SettingsHost.vb index f0dec10..0bd7ce8 100644 --- a/SCrawler/PluginsEnvironment/Hosts/SettingsHost.vb +++ b/SCrawler/PluginsEnvironment/Hosts/SettingsHost.vb @@ -204,7 +204,7 @@ Namespace Plugin.Hosts End If Next ElseIf m.MemberType = MemberTypes.Property Then - If Not m.GetCustomAttribute(Of Provider)() Is Nothing Then Providers.Add(m) + If m.GetCustomAttributes(Of Provider)().ListExists Then Providers.Add(m) End If End If End With @@ -220,13 +220,15 @@ Namespace Plugin.Hosts Updaters.Clear() End If If Providers.Count > 0 Then - Dim prov As Provider + Dim prov As IEnumerable(Of Provider) + Dim _prov As Provider For Each m In Providers - prov = m.GetCustomAttribute(Of Provider)() - i = PropList.FindIndex(Function(p) p.Name = prov.Name) - If i >= 0 Then - PropList(i).SetProvider(DirectCast(DirectCast(m, PropertyInfo).GetValue(Source), IFormatProvider), - m.GetCustomAttribute(Of Provider)().FieldsChecker) + prov = m.GetCustomAttributes(Of Provider)() + If prov.ListExists Then + For Each _prov In prov + i = PropList.FindIndex(Function(p) p.Name = _prov.Name) + If i >= 0 Then PropList(i).SetProvider(DirectCast(DirectCast(m, PropertyInfo).GetValue(Source), IFormatProvider), _prov) + Next End If Next Providers.Clear() diff --git a/SCrawler/SCrawler.vbproj b/SCrawler/SCrawler.vbproj index 8859e76..f0fe311 100644 --- a/SCrawler/SCrawler.vbproj +++ b/SCrawler/SCrawler.vbproj @@ -196,6 +196,13 @@ + + + OptionsForm.vb + + + Form + @@ -416,6 +423,9 @@ RedditViewSettingsForm.vb + + OptionsForm.vb + ChannelsStatsForm.vb diff --git a/SCrawler/UserSearchForm.vb b/SCrawler/UserSearchForm.vb index 00bc05a..3e6f935 100644 --- a/SCrawler/UserSearchForm.vb +++ b/SCrawler/UserSearchForm.vb @@ -94,56 +94,49 @@ Friend Class UserSearchForm LIST_SEARCH.BeginUpdate() ControlInvokeFast(LIST_SEARCH, Sub() LIST_SEARCH.Items.Clear()) Results.Clear() - Dim t$ = TXT_SEARCH.Text.Trim + Dim t$ = TXT_SEARCH.Text.StringTrim.StringToLower With Settings If Not t.IsEmptyString And .Users.Count > 0 Then Dim i% Dim s As Plugin.ExchangeOptions = Nothing - Dim cu As Boolean = False Dim __descr As Boolean = CH_SEARCH_IN_DESCR.Checked Dim __name As Boolean = CH_SEARCH_IN_NAME.Checked Dim __lbl As Boolean = CH_SEARCH_IN_LABEL.Checked - Dim _CheckUrl As Action(Of IUserData) = Sub(ByVal u As IUserData) - If cu AndAlso ((u.Site = s.SiteName Or u.HOST.Key = s.HostKey) And u.Name.ToLower = s.UserName) Then _ - Results.ListAddValue(New SearchResult(u, SearchResult.Modes.URL), RLP) - End Sub - Dim _CheckDescr As Action(Of IUserData) = Sub(ByVal u As IUserData) - If __descr AndAlso Not u.Description.IsEmptyString AndAlso - u.Description.Contains(t) Then _ - Results.ListAddValue(New SearchResult(u, SearchResult.Modes.Description), RLP) - End Sub - Dim _LabelPredicate As Predicate(Of String) = Function(l) l.ToLower.Contains(t) - Dim _CheckLabels As Action(Of IUserData) = Sub(ByVal u As IUserData) - If __lbl AndAlso u.Labels.ListExists AndAlso u.Labels.Exists(_LabelPredicate) Then _ - Results.ListAddValue(New SearchResult(u, SearchResult.Modes.Label), RLP) - End Sub + Dim __isUrl As Boolean = t.StartsWith("http") + Dim __urlFound As Boolean = False + Dim _p_url As Predicate(Of IUserData) = Function(u) __urlFound AndAlso ((u.Site = s.SiteName Or u.HOST.Key = s.HostKey) And u.Name.ToLower = s.UserName.ToLower) + Dim _p_descr As Predicate(Of IUserData) = Function(u) __descr AndAlso Not u.Description.IsEmptyString AndAlso u.Description.ToLower.Contains(t) + Dim _p_labels_p As Predicate(Of String) = Function(l) l.ToLower.Contains(t) + Dim _p_labels As Predicate(Of IUserData) = Function(u) __lbl AndAlso u.Labels.ListExists AndAlso u.Labels.Exists(_p_labels_p) + Dim _addValue As Action(Of IUserData, SearchResult.Modes, Predicate(Of IUserData)) = Sub(u, m, p) If p.Invoke(u) Then Results.ListAddValue(New SearchResult(u, m), RLP) - If t.Length >= 4 AndAlso t.StartsWith("http") Then + If __isUrl Then For Each p In Settings.Plugins s = p.Settings.IsMyUser(t) If Not s.UserName.IsEmptyString Then Exit For Next + __urlFound = Not s.UserName.IsEmptyString End If - cu = Not s.UserName.IsEmptyString - t = t.ToLower For Each user As IUserData In .Users - If __name AndAlso user.Name.ToLower.Contains(t) Then Results.ListAddValue(New SearchResult(user, SearchResult.Modes.Name), RLP) + If Not __isUrl AndAlso __name AndAlso user.Name.ToLower.Contains(t) Then Results.ListAddValue(New SearchResult(user, SearchResult.Modes.Name), RLP) If user.IsCollection Then With DirectCast(user, UserDataBind) If .Count > 0 Then For i = 0 To .Count - 1 - If __name AndAlso .Item(i).Name.ToLower = t Then Results.ListAddValue(New SearchResult(.Item(i), SearchResult.Modes.Name), RLP) - _CheckUrl(.Item(i)) - _CheckDescr(.Item(i)) - _CheckLabels(.Item(i)) + With .Item(i) + If Not __isUrl AndAlso __name AndAlso .Self.Name.ToLower = t Then Results.ListAddValue(New SearchResult(.Self, SearchResult.Modes.Name), RLP) + _addValue(.Self, SearchResult.Modes.URL, _p_url) + _addValue(.Self, SearchResult.Modes.Description, _p_descr) + _addValue(.Self, SearchResult.Modes.Label, _p_labels) + End With Next End If End With Else - _CheckUrl(user) - _CheckDescr(user) - _CheckLabels(user) + _addValue(user, SearchResult.Modes.URL, _p_url) + _addValue(user, SearchResult.Modes.Description, _p_descr) + _addValue(user, SearchResult.Modes.Label, _p_labels) End If Next If Results.Count > 0 Then