• R/O
  • SSH
  • HTTPS

instalikes: Commit


Commit MetaInfo

Revision4 (tree)
Zeit2019-02-07 01:20:29
Autorderekwildstar

Log Message

Commit inicial

Ändern Zusammenfassung

Diff

--- trunk/dev/dba/InstaLikes.sql (nonexistent)
+++ trunk/dev/dba/InstaLikes.sql (revision 4)
@@ -0,0 +1,65 @@
1+--
2+-- File generated with SQLiteStudio v3.2.1 on sex fev 1 14:47:42 2019
3+--
4+-- Text encoding used: System
5+--
6+PRAGMA foreign_keys = off;
7+BEGIN TRANSACTION;
8+
9+-- Table: followers
10+DROP TABLE IF EXISTS followers;
11+
12+CREATE TABLE followers (
13+ id INTEGER PRIMARY KEY ON CONFLICT ROLLBACK AUTOINCREMENT
14+ NOT NULL ON CONFLICT ROLLBACK,
15+ followedid VARCHAR (20) NOT NULL ON CONFLICT ROLLBACK
16+ CONSTRAINT user_followers_followed_fk REFERENCES user (id) ON DELETE CASCADE
17+ ON UPDATE CASCADE,
18+ followerid VARCHAR (20) NOT NULL ON CONFLICT ROLLBACK
19+ CONSTRAINT user_followers_followed_fk REFERENCES user (id) ON DELETE CASCADE
20+ ON UPDATE CASCADE,
21+ CONSTRAINT followed_follower_uc UNIQUE (
22+ followedid,
23+ followerid
24+ )
25+ ON CONFLICT ROLLBACK
26+);
27+
28+
29+-- Table: medias
30+DROP TABLE IF EXISTS medias;
31+
32+CREATE TABLE medias (
33+ id VARCHAR (20) PRIMARY KEY ON CONFLICT ROLLBACK
34+ NOT NULL ON CONFLICT ROLLBACK,
35+ shortcode VARCHAR (50) NOT NULL ON CONFLICT ROLLBACK,
36+ width INTEGER NOT NULL ON CONFLICT ROLLBACK,
37+ height INTEGER NOT NULL ON CONFLICT ROLLBACK,
38+ userid VARCHAR (20) CONSTRAINT user_media_fk REFERENCES user (id) ON DELETE CASCADE
39+ ON UPDATE CASCADE
40+ NOT NULL ON CONFLICT ROLLBACK
41+);
42+
43+
44+-- Table: user
45+DROP TABLE IF EXISTS user;
46+
47+CREATE TABLE user (
48+ id VARCHAR (20) PRIMARY KEY ON CONFLICT ROLLBACK
49+ NOT NULL ON CONFLICT ROLLBACK,
50+ username VARCHAR (20) CONSTRAINT users_username_uc UNIQUE ON CONFLICT ROLLBACK
51+ NOT NULL ON CONFLICT ROLLBACK,
52+ realname VARCHAR (64) NOT NULL ON CONFLICT ROLLBACK,
53+ pictureurl VARCHAR (255),
54+ biography TEXT,
55+ isprivate BOOLEAN NOT NULL,
56+ isverified BOOLEAN,
57+ isbusinessaccount BOOLEAN,
58+ followers BIGINT,
59+ following BIGINT,
60+ medias BIGINT
61+);
62+
63+
64+COMMIT TRANSACTION;
65+PRAGMA foreign_keys = on;
--- trunk/prj/InstaLikes.dpr (nonexistent)
+++ trunk/prj/InstaLikes.dpr (revision 4)
@@ -0,0 +1,29 @@
1+program InstaLikes;
2+
3+uses
4+ {$IFDEF DEBUG}
5+// FastMM4,
6+ {$ENDIF }
7+ Vcl.Forms,
8+ UFORMPrincipal in '..\src\UFORMPrincipal.pas' {FORMPrincipal},
9+ Vcl.Themes,
10+ Vcl.Styles,
11+ UDAMOPrincipal in '..\src\UDAMOPrincipal.pas' {DAMOPrincipal: TDataModule},
12+ UFORMStatus in '..\src\UFORMStatus.pas' {FORMStatus},
13+ UFORMAddUserParams in '..\src\UFORMAddUserParams.pas' {FORMAddUserParams};
14+
15+{$R *.res}
16+
17+begin
18+ {$IFDEF DEBUG}
19+// ReportMemoryLeaksOnShutdown := True;
20+// FullDebugModeScanMemoryPoolBeforeEveryOperation := True;
21+// SuppressMessageBoxes:=False;
22+ {$ENDIF}
23+
24+ Application.Initialize;
25+ Application.MainFormOnTaskbar := True;
26+ Application.CreateForm(TDAMOPrincipal, DAMOPrincipal);
27+ Application.CreateForm(TFORMPrincipal, FORMPrincipal);
28+ Application.Run;
29+end.
--- trunk/prj/InstaLikes.dproj (nonexistent)
+++ trunk/prj/InstaLikes.dproj (revision 4)
@@ -0,0 +1,586 @@
1+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+ <PropertyGroup>
3+ <ProjectGuid>{1A2D6B31-BE24-4483-B88E-35711462F427}</ProjectGuid>
4+ <ProjectVersion>18.4</ProjectVersion>
5+ <FrameworkType>VCL</FrameworkType>
6+ <MainSource>InstaLikes.dpr</MainSource>
7+ <Base>True</Base>
8+ <Config Condition="'$(Config)'==''">Debug</Config>
9+ <Platform Condition="'$(Platform)'==''">Win32</Platform>
10+ <TargetedPlatforms>1</TargetedPlatforms>
11+ <AppType>Application</AppType>
12+ </PropertyGroup>
13+ <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
14+ <Base>true</Base>
15+ </PropertyGroup>
16+ <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
17+ <Base_Win32>true</Base_Win32>
18+ <CfgParent>Base</CfgParent>
19+ <Base>true</Base>
20+ </PropertyGroup>
21+ <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
22+ <Base_Win64>true</Base_Win64>
23+ <CfgParent>Base</CfgParent>
24+ <Base>true</Base>
25+ </PropertyGroup>
26+ <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
27+ <Cfg_1>true</Cfg_1>
28+ <CfgParent>Base</CfgParent>
29+ <Base>true</Base>
30+ </PropertyGroup>
31+ <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
32+ <Cfg_1_Win32>true</Cfg_1_Win32>
33+ <CfgParent>Cfg_1</CfgParent>
34+ <Cfg_1>true</Cfg_1>
35+ <Base>true</Base>
36+ </PropertyGroup>
37+ <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
38+ <Cfg_2>true</Cfg_2>
39+ <CfgParent>Base</CfgParent>
40+ <Base>true</Base>
41+ </PropertyGroup>
42+ <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
43+ <Cfg_2_Win32>true</Cfg_2_Win32>
44+ <CfgParent>Cfg_2</CfgParent>
45+ <Cfg_2>true</Cfg_2>
46+ <Base>true</Base>
47+ </PropertyGroup>
48+ <PropertyGroup Condition="'$(Base)'!=''">
49+ <DCC_DcuOutput>..\bin\dcu</DCC_DcuOutput>
50+ <DCC_ExeOutput>..\bin\</DCC_ExeOutput>
51+ <DCC_E>false</DCC_E>
52+ <DCC_N>false</DCC_N>
53+ <DCC_S>false</DCC_S>
54+ <DCC_F>false</DCC_F>
55+ <DCC_K>false</DCC_K>
56+ <DCC_UsePackage>RESTComponents;FireDACIBDriver;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;FireDAC;FireDACSqliteDriver;soaprtl;soapmidas;$(DCC_UsePackage)</DCC_UsePackage>
57+ <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
58+ <Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
59+ <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
60+ <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
61+ <SanitizedProjectName>InstaLikes</SanitizedProjectName>
62+ <VerInfo_Locale>1046</VerInfo_Locale>
63+ <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
64+ </PropertyGroup>
65+ <PropertyGroup Condition="'$(Base_Win32)'!=''">
66+ <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;svnui;dclRBDBE1925;FireDACADSDriver;rbRIDE1925;vcltouch;vcldb;bindcompfmx;svn;inetdb;KRKOTANotifiersR;rbTC1925;FmxTeeUI;rbIDE1925;fmx;fmxdae;dbexpress;IndyCore;vclx;dsnap;VCLRESTComponents;rbTCUI1925;rbFireDAC1925;PNGComponentsR;rbRTL1925;rbDB1925;vclie;bindengine;DBXMySQLDriver;dclRBFireDAC1925;FireDACMySQLDriver;FireDACCommonODBC;dclRBE1925;rbRCL1925;UIRibbonPackageDR;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;TBGWebCharts;IndySystem;dsnapcon;rbDBE1925;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDACPgDriver;FMXTee;DbxCommonDriver;rbUSER1925;rbDIDE1925;rbADO1925;Tee;rbRest1925;xmlrtl;rbUSERDesign1925;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;rbRAP1925;bindcomp;appanalytics;rbDAD1925;IndyIPClient;rbBDE1925;bindcompvcl;TeeUI;rbCIDE1925;dbxcds;VclSmp;adortl;FireDACConnR;UserControlR;dsnapxml;dclRBADO1925;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
67+ <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
68+ <BT_BuildType>Debug</BT_BuildType>
69+ <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
70+ <VerInfo_Locale>1033</VerInfo_Locale>
71+ <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
72+ </PropertyGroup>
73+ <PropertyGroup Condition="'$(Base_Win64)'!=''">
74+ <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;vcltouch;vcldb;bindcompfmx;inetdb;FmxTeeUI;fmx;fmxdae;dbexpress;IndyCore;vclx;dsnap;VCLRESTComponents;vclie;bindengine;DBXMySQLDriver;FireDACMySQLDriver;FireDACCommonODBC;UIRibbonPackageDR;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;IndySystem;dsnapcon;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDACPgDriver;FMXTee;DbxCommonDriver;Tee;xmlrtl;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
75+ </PropertyGroup>
76+ <PropertyGroup Condition="'$(Cfg_1)'!=''">
77+ <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
78+ <DCC_DebugDCUs>true</DCC_DebugDCUs>
79+ <DCC_Optimize>false</DCC_Optimize>
80+ <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
81+ <DCC_MapFile>3</DCC_MapFile>
82+ </PropertyGroup>
83+ <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
84+ <AppEnableHighDPI>true</AppEnableHighDPI>
85+ <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
86+ <VerInfo_Locale>1033</VerInfo_Locale>
87+ <Icon_MainIcon>..\res\icons8-heart-health-96.ico</Icon_MainIcon>
88+ <UWP_DelphiLogo44>..\res\icons8-heart-health-96.png</UWP_DelphiLogo44>
89+ <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
90+ <UWP_DelphiLogo150>..\res\icons8-heart-health-96.png</UWP_DelphiLogo150>
91+ </PropertyGroup>
92+ <PropertyGroup Condition="'$(Cfg_2)'!=''">
93+ <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
94+ <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
95+ <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
96+ <DCC_DebugInformation>0</DCC_DebugInformation>
97+ </PropertyGroup>
98+ <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
99+ <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
100+ <AppEnableHighDPI>true</AppEnableHighDPI>
101+ <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
102+ <VerInfo_Locale>1033</VerInfo_Locale>
103+ </PropertyGroup>
104+ <ItemGroup>
105+ <DelphiCompile Include="$(MainSource)">
106+ <MainSource>MainSource</MainSource>
107+ </DelphiCompile>
108+ <DCCReference Include="..\src\UFORMPrincipal.pas">
109+ <Form>FORMPrincipal</Form>
110+ </DCCReference>
111+ <DCCReference Include="..\src\UDAMOPrincipal.pas">
112+ <Form>DAMOPrincipal</Form>
113+ <DesignClass>TDataModule</DesignClass>
114+ </DCCReference>
115+ <DCCReference Include="..\src\UFORMStatus.pas">
116+ <Form>FORMStatus</Form>
117+ </DCCReference>
118+ <DCCReference Include="..\src\UFORMAddUserParams.pas">
119+ <Form>FORMAddUserParams</Form>
120+ </DCCReference>
121+ <BuildConfiguration Include="Release">
122+ <Key>Cfg_2</Key>
123+ <CfgParent>Base</CfgParent>
124+ </BuildConfiguration>
125+ <BuildConfiguration Include="Base">
126+ <Key>Base</Key>
127+ </BuildConfiguration>
128+ <BuildConfiguration Include="Debug">
129+ <Key>Cfg_1</Key>
130+ <CfgParent>Base</CfgParent>
131+ </BuildConfiguration>
132+ </ItemGroup>
133+ <ProjectExtensions>
134+ <Borland.Personality>Delphi.Personality.12</Borland.Personality>
135+ <Borland.ProjectType>Application</Borland.ProjectType>
136+ <BorlandProject>
137+ <Delphi.Personality>
138+ <Source>
139+ <Source Name="MainSource">InstaLikes.dpr</Source>
140+ </Source>
141+ <Excluded_Packages>
142+ <Excluded_Packages Name="$(BDSBIN)\dcloffice2k250.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
143+ <Excluded_Packages Name="$(BDSBIN)\dclofficexp250.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
144+ </Excluded_Packages>
145+ </Delphi.Personality>
146+ <Deployment Version="3">
147+ <DeployFile LocalName="..\bin\InstaLikes.exe" Configuration="Debug" Class="ProjectOutput">
148+ <Platform Name="Win32">
149+ <RemoteName>InstaLikes.exe</RemoteName>
150+ <Overwrite>true</Overwrite>
151+ </Platform>
152+ </DeployFile>
153+ <DeployFile LocalName="..\res\icons8-heart-health-96.png" Configuration="Debug" Class="UWP_DelphiLogo44">
154+ <Platform Name="Win32">
155+ <RemoteDir>Assets\</RemoteDir>
156+ <RemoteName>Logo44x44.png</RemoteName>
157+ <Overwrite>true</Overwrite>
158+ </Platform>
159+ </DeployFile>
160+ <DeployClass Name="AdditionalDebugSymbols">
161+ <Platform Name="iOSSimulator">
162+ <Operation>1</Operation>
163+ </Platform>
164+ <Platform Name="OSX32">
165+ <RemoteDir>Contents\MacOS</RemoteDir>
166+ <Operation>1</Operation>
167+ </Platform>
168+ <Platform Name="Win32">
169+ <RemoteDir>Contents\MacOS</RemoteDir>
170+ <Operation>0</Operation>
171+ </Platform>
172+ </DeployClass>
173+ <DeployClass Name="AndroidClassesDexFile">
174+ <Platform Name="Android">
175+ <RemoteDir>classes</RemoteDir>
176+ <Operation>1</Operation>
177+ </Platform>
178+ </DeployClass>
179+ <DeployClass Name="AndroidGDBServer">
180+ <Platform Name="Android">
181+ <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
182+ <Operation>1</Operation>
183+ </Platform>
184+ </DeployClass>
185+ <DeployClass Name="AndroidLibnativeArmeabiFile">
186+ <Platform Name="Android">
187+ <RemoteDir>library\lib\armeabi</RemoteDir>
188+ <Operation>1</Operation>
189+ </Platform>
190+ </DeployClass>
191+ <DeployClass Name="AndroidLibnativeMipsFile">
192+ <Platform Name="Android">
193+ <RemoteDir>library\lib\mips</RemoteDir>
194+ <Operation>1</Operation>
195+ </Platform>
196+ </DeployClass>
197+ <DeployClass Name="AndroidServiceOutput">
198+ <Platform Name="Android">
199+ <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
200+ <Operation>1</Operation>
201+ </Platform>
202+ </DeployClass>
203+ <DeployClass Name="AndroidSplashImageDef">
204+ <Platform Name="Android">
205+ <RemoteDir>res\drawable</RemoteDir>
206+ <Operation>1</Operation>
207+ </Platform>
208+ </DeployClass>
209+ <DeployClass Name="AndroidSplashStyles">
210+ <Platform Name="Android">
211+ <RemoteDir>res\values</RemoteDir>
212+ <Operation>1</Operation>
213+ </Platform>
214+ </DeployClass>
215+ <DeployClass Name="Android_DefaultAppIcon">
216+ <Platform Name="Android">
217+ <RemoteDir>res\drawable</RemoteDir>
218+ <Operation>1</Operation>
219+ </Platform>
220+ </DeployClass>
221+ <DeployClass Name="Android_LauncherIcon144">
222+ <Platform Name="Android">
223+ <RemoteDir>res\drawable-xxhdpi</RemoteDir>
224+ <Operation>1</Operation>
225+ </Platform>
226+ </DeployClass>
227+ <DeployClass Name="Android_LauncherIcon36">
228+ <Platform Name="Android">
229+ <RemoteDir>res\drawable-ldpi</RemoteDir>
230+ <Operation>1</Operation>
231+ </Platform>
232+ </DeployClass>
233+ <DeployClass Name="Android_LauncherIcon48">
234+ <Platform Name="Android">
235+ <RemoteDir>res\drawable-mdpi</RemoteDir>
236+ <Operation>1</Operation>
237+ </Platform>
238+ </DeployClass>
239+ <DeployClass Name="Android_LauncherIcon72">
240+ <Platform Name="Android">
241+ <RemoteDir>res\drawable-hdpi</RemoteDir>
242+ <Operation>1</Operation>
243+ </Platform>
244+ </DeployClass>
245+ <DeployClass Name="Android_LauncherIcon96">
246+ <Platform Name="Android">
247+ <RemoteDir>res\drawable-xhdpi</RemoteDir>
248+ <Operation>1</Operation>
249+ </Platform>
250+ </DeployClass>
251+ <DeployClass Name="Android_SplashImage426">
252+ <Platform Name="Android">
253+ <RemoteDir>res\drawable-small</RemoteDir>
254+ <Operation>1</Operation>
255+ </Platform>
256+ </DeployClass>
257+ <DeployClass Name="Android_SplashImage470">
258+ <Platform Name="Android">
259+ <RemoteDir>res\drawable-normal</RemoteDir>
260+ <Operation>1</Operation>
261+ </Platform>
262+ </DeployClass>
263+ <DeployClass Name="Android_SplashImage640">
264+ <Platform Name="Android">
265+ <RemoteDir>res\drawable-large</RemoteDir>
266+ <Operation>1</Operation>
267+ </Platform>
268+ </DeployClass>
269+ <DeployClass Name="Android_SplashImage960">
270+ <Platform Name="Android">
271+ <RemoteDir>res\drawable-xlarge</RemoteDir>
272+ <Operation>1</Operation>
273+ </Platform>
274+ </DeployClass>
275+ <DeployClass Name="DebugSymbols">
276+ <Platform Name="iOSSimulator">
277+ <Operation>1</Operation>
278+ </Platform>
279+ <Platform Name="OSX32">
280+ <RemoteDir>Contents\MacOS</RemoteDir>
281+ <Operation>1</Operation>
282+ </Platform>
283+ <Platform Name="Win32">
284+ <Operation>0</Operation>
285+ </Platform>
286+ </DeployClass>
287+ <DeployClass Name="DependencyFramework">
288+ <Platform Name="OSX32">
289+ <RemoteDir>Contents\MacOS</RemoteDir>
290+ <Operation>1</Operation>
291+ <Extensions>.framework</Extensions>
292+ </Platform>
293+ <Platform Name="Win32">
294+ <Operation>0</Operation>
295+ </Platform>
296+ </DeployClass>
297+ <DeployClass Name="DependencyModule">
298+ <Platform Name="iOSDevice32">
299+ <Operation>1</Operation>
300+ <Extensions>.dylib</Extensions>
301+ </Platform>
302+ <Platform Name="iOSDevice64">
303+ <Operation>1</Operation>
304+ <Extensions>.dylib</Extensions>
305+ </Platform>
306+ <Platform Name="iOSSimulator">
307+ <Operation>1</Operation>
308+ <Extensions>.dylib</Extensions>
309+ </Platform>
310+ <Platform Name="OSX32">
311+ <RemoteDir>Contents\MacOS</RemoteDir>
312+ <Operation>1</Operation>
313+ <Extensions>.dylib</Extensions>
314+ </Platform>
315+ <Platform Name="Win32">
316+ <Operation>0</Operation>
317+ <Extensions>.dll;.bpl</Extensions>
318+ </Platform>
319+ </DeployClass>
320+ <DeployClass Required="true" Name="DependencyPackage">
321+ <Platform Name="iOSDevice32">
322+ <Operation>1</Operation>
323+ <Extensions>.dylib</Extensions>
324+ </Platform>
325+ <Platform Name="iOSDevice64">
326+ <Operation>1</Operation>
327+ <Extensions>.dylib</Extensions>
328+ </Platform>
329+ <Platform Name="iOSSimulator">
330+ <Operation>1</Operation>
331+ <Extensions>.dylib</Extensions>
332+ </Platform>
333+ <Platform Name="OSX32">
334+ <RemoteDir>Contents\MacOS</RemoteDir>
335+ <Operation>1</Operation>
336+ <Extensions>.dylib</Extensions>
337+ </Platform>
338+ <Platform Name="Win32">
339+ <Operation>0</Operation>
340+ <Extensions>.bpl</Extensions>
341+ </Platform>
342+ </DeployClass>
343+ <DeployClass Name="File">
344+ <Platform Name="Android">
345+ <Operation>0</Operation>
346+ </Platform>
347+ <Platform Name="iOSDevice32">
348+ <Operation>0</Operation>
349+ </Platform>
350+ <Platform Name="iOSDevice64">
351+ <Operation>0</Operation>
352+ </Platform>
353+ <Platform Name="iOSSimulator">
354+ <Operation>0</Operation>
355+ </Platform>
356+ <Platform Name="OSX32">
357+ <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
358+ <Operation>0</Operation>
359+ </Platform>
360+ <Platform Name="Win32">
361+ <Operation>0</Operation>
362+ </Platform>
363+ </DeployClass>
364+ <DeployClass Name="iPad_Launch1024">
365+ <Platform Name="iOSDevice32">
366+ <Operation>1</Operation>
367+ </Platform>
368+ <Platform Name="iOSDevice64">
369+ <Operation>1</Operation>
370+ </Platform>
371+ <Platform Name="iOSSimulator">
372+ <Operation>1</Operation>
373+ </Platform>
374+ </DeployClass>
375+ <DeployClass Name="iPad_Launch1536">
376+ <Platform Name="iOSDevice32">
377+ <Operation>1</Operation>
378+ </Platform>
379+ <Platform Name="iOSDevice64">
380+ <Operation>1</Operation>
381+ </Platform>
382+ <Platform Name="iOSSimulator">
383+ <Operation>1</Operation>
384+ </Platform>
385+ </DeployClass>
386+ <DeployClass Name="iPad_Launch2048">
387+ <Platform Name="iOSDevice32">
388+ <Operation>1</Operation>
389+ </Platform>
390+ <Platform Name="iOSDevice64">
391+ <Operation>1</Operation>
392+ </Platform>
393+ <Platform Name="iOSSimulator">
394+ <Operation>1</Operation>
395+ </Platform>
396+ </DeployClass>
397+ <DeployClass Name="iPad_Launch768">
398+ <Platform Name="iOSDevice32">
399+ <Operation>1</Operation>
400+ </Platform>
401+ <Platform Name="iOSDevice64">
402+ <Operation>1</Operation>
403+ </Platform>
404+ <Platform Name="iOSSimulator">
405+ <Operation>1</Operation>
406+ </Platform>
407+ </DeployClass>
408+ <DeployClass Name="iPhone_Launch320">
409+ <Platform Name="iOSDevice32">
410+ <Operation>1</Operation>
411+ </Platform>
412+ <Platform Name="iOSDevice64">
413+ <Operation>1</Operation>
414+ </Platform>
415+ <Platform Name="iOSSimulator">
416+ <Operation>1</Operation>
417+ </Platform>
418+ </DeployClass>
419+ <DeployClass Name="iPhone_Launch640">
420+ <Platform Name="iOSDevice32">
421+ <Operation>1</Operation>
422+ </Platform>
423+ <Platform Name="iOSDevice64">
424+ <Operation>1</Operation>
425+ </Platform>
426+ <Platform Name="iOSSimulator">
427+ <Operation>1</Operation>
428+ </Platform>
429+ </DeployClass>
430+ <DeployClass Name="iPhone_Launch640x1136">
431+ <Platform Name="iOSDevice32">
432+ <Operation>1</Operation>
433+ </Platform>
434+ <Platform Name="iOSDevice64">
435+ <Operation>1</Operation>
436+ </Platform>
437+ <Platform Name="iOSSimulator">
438+ <Operation>1</Operation>
439+ </Platform>
440+ </DeployClass>
441+ <DeployClass Name="ProjectAndroidManifest">
442+ <Platform Name="Android">
443+ <Operation>1</Operation>
444+ </Platform>
445+ </DeployClass>
446+ <DeployClass Name="ProjectiOSDeviceDebug">
447+ <Platform Name="iOSDevice32">
448+ <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
449+ <Operation>1</Operation>
450+ </Platform>
451+ <Platform Name="iOSDevice64">
452+ <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
453+ <Operation>1</Operation>
454+ </Platform>
455+ </DeployClass>
456+ <DeployClass Name="ProjectiOSDeviceResourceRules">
457+ <Platform Name="iOSDevice32">
458+ <Operation>1</Operation>
459+ </Platform>
460+ <Platform Name="iOSDevice64">
461+ <Operation>1</Operation>
462+ </Platform>
463+ </DeployClass>
464+ <DeployClass Name="ProjectiOSEntitlements">
465+ <Platform Name="iOSDevice32">
466+ <RemoteDir>..\</RemoteDir>
467+ <Operation>1</Operation>
468+ </Platform>
469+ <Platform Name="iOSDevice64">
470+ <RemoteDir>..\</RemoteDir>
471+ <Operation>1</Operation>
472+ </Platform>
473+ </DeployClass>
474+ <DeployClass Name="ProjectiOSInfoPList">
475+ <Platform Name="iOSDevice32">
476+ <Operation>1</Operation>
477+ </Platform>
478+ <Platform Name="iOSDevice64">
479+ <Operation>1</Operation>
480+ </Platform>
481+ <Platform Name="iOSSimulator">
482+ <Operation>1</Operation>
483+ </Platform>
484+ </DeployClass>
485+ <DeployClass Name="ProjectiOSResource">
486+ <Platform Name="iOSDevice32">
487+ <Operation>1</Operation>
488+ </Platform>
489+ <Platform Name="iOSDevice64">
490+ <Operation>1</Operation>
491+ </Platform>
492+ <Platform Name="iOSSimulator">
493+ <Operation>1</Operation>
494+ </Platform>
495+ </DeployClass>
496+ <DeployClass Name="ProjectOSXEntitlements">
497+ <Platform Name="OSX32">
498+ <RemoteDir>..\</RemoteDir>
499+ <Operation>1</Operation>
500+ </Platform>
501+ </DeployClass>
502+ <DeployClass Name="ProjectOSXInfoPList">
503+ <Platform Name="OSX32">
504+ <RemoteDir>Contents</RemoteDir>
505+ <Operation>1</Operation>
506+ </Platform>
507+ </DeployClass>
508+ <DeployClass Name="ProjectOSXResource">
509+ <Platform Name="OSX32">
510+ <RemoteDir>Contents\Resources</RemoteDir>
511+ <Operation>1</Operation>
512+ </Platform>
513+ </DeployClass>
514+ <DeployClass Required="true" Name="ProjectOutput">
515+ <Platform Name="Android">
516+ <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
517+ <Operation>1</Operation>
518+ </Platform>
519+ <Platform Name="iOSDevice32">
520+ <Operation>1</Operation>
521+ </Platform>
522+ <Platform Name="iOSDevice64">
523+ <Operation>1</Operation>
524+ </Platform>
525+ <Platform Name="iOSSimulator">
526+ <Operation>1</Operation>
527+ </Platform>
528+ <Platform Name="Linux64">
529+ <Operation>1</Operation>
530+ </Platform>
531+ <Platform Name="OSX32">
532+ <RemoteDir>Contents\MacOS</RemoteDir>
533+ <Operation>1</Operation>
534+ </Platform>
535+ <Platform Name="Win32">
536+ <Operation>0</Operation>
537+ </Platform>
538+ </DeployClass>
539+ <DeployClass Name="ProjectUWPManifest">
540+ <Platform Name="Win32">
541+ <Operation>1</Operation>
542+ </Platform>
543+ <Platform Name="Win64">
544+ <Operation>1</Operation>
545+ </Platform>
546+ </DeployClass>
547+ <DeployClass Name="UWP_DelphiLogo150">
548+ <Platform Name="Win32">
549+ <RemoteDir>Assets</RemoteDir>
550+ <Operation>1</Operation>
551+ </Platform>
552+ <Platform Name="Win64">
553+ <RemoteDir>Assets</RemoteDir>
554+ <Operation>1</Operation>
555+ </Platform>
556+ </DeployClass>
557+ <DeployClass Name="UWP_DelphiLogo44">
558+ <Platform Name="Win32">
559+ <RemoteDir>Assets</RemoteDir>
560+ <Operation>1</Operation>
561+ </Platform>
562+ <Platform Name="Win64">
563+ <RemoteDir>Assets</RemoteDir>
564+ <Operation>1</Operation>
565+ </Platform>
566+ </DeployClass>
567+ <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
568+ <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
569+ <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
570+ <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
571+ <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
572+ <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
573+ <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
574+ <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
575+ </Deployment>
576+ <Platforms>
577+ <Platform value="Win32">True</Platform>
578+ <Platform value="Win64">False</Platform>
579+ </Platforms>
580+ </BorlandProject>
581+ <ProjectFileVersion>12</ProjectFileVersion>
582+ </ProjectExtensions>
583+ <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
584+ <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
585+ <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
586+</Project>
--- trunk/src/UDAMOPrincipal.pas (nonexistent)
+++ trunk/src/UDAMOPrincipal.pas (revision 4)
@@ -0,0 +1,1483 @@
1+unit UDAMOPrincipal;
2+
3+interface
4+
5+uses
6+ System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option,
7+ FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
8+ FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.SQLite,
9+ FireDAC.Phys.SQLiteDef, FireDAC.Stan.ExprFuncs, FireDAC.VCLUI.Wait, Data.DB,
10+ FireDAC.Comp.Client, System.ImageList, Vcl.ImgList, Vcl.Controls,
11+ UPngImageList, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf,
12+ FireDAC.DApt, FireDAC.Comp.DataSet,
13+ KRK.Components.AdditionalControls.BalloonHint, Vcl.ExtCtrls, Vcl.Menus,
14+ Vcl.PlatformDefaultStyleActnCtrls, Vcl.ActnPopup, System.Actions,
15+ Vcl.ActnList, Vcl.ActnMan, KRK.Components.DataControls.DBGrid, JSON,
16+ Vcl.Forms;
17+
18+type
19+ TMedia = record
20+ Id: String;
21+ ShortCode: String;
22+ Width: Word;
23+ Height: Word;
24+ end;
25+
26+ TMedias = array of TMedia;
27+
28+ TInstagramUser = record
29+ id: String;
30+ UserName: String;
31+ RealName: String;
32+ PictureURL: String;
33+ Biography: String;
34+ IsPrivate: Boolean;
35+ IsVerified: Boolean;
36+ Followers: Cardinal;
37+ Following: Cardinal;
38+ IsBusinessAccount: Boolean;
39+ FollowedByViewer: Boolean;
40+ MediasTotal: Cardinal;
41+ LastestMedia: TMedias;
42+ end;
43+
44+ TInstagramUsers = array of TInstagramUser;
45+
46+ TRelation = (rUnknown,rMoreThan,rLessThan);
47+
48+ TAddFollowersParams = record
49+ UsersToRegister: Cardinal;
50+ IncludePrivate: Boolean;
51+ IncludeBusinessAccount: Boolean;
52+ IncludeVerified: Boolean;
53+ IncludeFollowedByViewer: Boolean;
54+ FollowingCount: Cardinal;
55+ FollowingRelation: TRelation;
56+ FollowersCount: Cardinal;
57+ FollowersRelation: TRelation;
58+ end;
59+
60+ EInstagram = Exception;
61+
62+ TDAMOPrincipal = class(TDataModule)
63+ FDCO: TFDConnection;
64+ PNIL1: TPngImageList;
65+ PNIL2: TPngImageList;
66+ FDTAUser: TFDTable;
67+ DASOUser: TDataSource;
68+ FDTAUserid: TWideStringField;
69+ FDTAUserusername: TWideStringField;
70+ FDTAUserrealname: TWideStringField;
71+ FDTAUserpictureurl: TWideStringField;
72+ FDTAUserbiography: TWideMemoField;
73+ FDTAUserisprivate: TBooleanField;
74+ FDTAUserisverified: TBooleanField;
75+ FDTAUserisbusinessaccount: TBooleanField;
76+ FDTAUserfollowers: TLargeintField;
77+ FDTAUserfollowing: TLargeintField;
78+ FDTAUsermedias: TLargeintField;
79+ KRBH: TKRKBalloonHint;
80+ PPAB: TPopupActionBar;
81+ AMAN: TActionManager;
82+ ACTNAddFollowers: TAction;
83+ MNUIAddUpdateFollowers: TMenuItem;
84+ FDTAMedias: TFDTable;
85+ FDTAMediasid: TWideStringField;
86+ FDTAMediasshortcode: TWideStringField;
87+ FDTAMediaswidth: TIntegerField;
88+ FDTAMediasheight: TIntegerField;
89+ FDTAMediasuserid: TWideStringField;
90+ DASOMedias: TDataSource;
91+ ACTNUpdateUser: TAction;
92+ FDTAFollowers: TFDTable;
93+ DASOFollowers: TDataSource;
94+ FDTAFollowersid: TFDAutoIncField;
95+ FDTAFollowersfollowingid: TWideStringField;
96+ FDTAFollowersfollowerid: TWideStringField;
97+ FDTAMediaswasliked: TBooleanField;
98+ ACTNSelectFollowers: TAction;
99+ MNUISelectFollowers: TMenuItem;
100+ ACTNSelectAll: TAction;
101+ ACTNSelectNone: TAction;
102+ ACTNSelectInverse: TAction;
103+ ACTNLikeAll: TAction;
104+ ACTNLikeLastest: TAction;
105+ ACTNAddUser: TAction;
106+ procedure FDCOBeforeConnect(Sender: TObject);
107+ procedure DoClearFlag(Sender: TField; var Text: string; DisplayText: Boolean);
108+ procedure FDTAUserAfterScroll(DataSet: TDataSet);
109+ procedure FDTAUserfollowersGetText(Sender: TField; var Text: string; DisplayText: Boolean);
110+ procedure FDTAUserfollowingGetText(Sender: TField; var Text: string; DisplayText: Boolean);
111+ procedure FDTAUsermediasGetText(Sender: TField; var Text: string; DisplayText: Boolean);
112+ procedure DataModuleCreate(Sender: TObject);
113+ procedure ACTNAddFollowersExecute(Sender: TObject);
114+ procedure ACTNUpdateUserExecute(Sender: TObject);
115+ procedure ACTNSelectFollowersExecute(Sender: TObject);
116+ procedure ACTNSelectAllExecute(Sender: TObject);
117+ procedure ACTNSelectNoneExecute(Sender: TObject);
118+ procedure ACTNSelectInverseExecute(Sender: TObject);
119+ procedure ACTNLikeLastestExecute(Sender: TObject);
120+ procedure ACTNAddUserExecute(Sender: TObject);
121+ private
122+ { Private declarations }
123+ FRequestsSoFar: Cardinal;
124+ FQueryHash: String;
125+ FWaitSeconds: Byte;
126+ FAddFollowersParams: TAddFollowersParams;
127+ function UserExists(AUserName: String): Boolean;
128+ procedure LoadProfilePicture(AUserId: String; APictureURL: String; AImage: TImage);
129+ procedure DownloadProfilePicture(AUserId: String; APictureURL: String);
130+ procedure UpdateRequestsSoFar;
131+ // Adiciona o usuário de forma completa, com as últimas mídias postadas
132+ // sendo salvas na tabela medias. Este método NÃO adiciona os seguidores do
133+ // usuário
134+ procedure AddUser(const AUserName: String; const AFollowingId: String = ''); overload;
135+ // Esta função adiciona ou atualiza o usuário informado. Ela retorna true
136+ // apenas quando o usuário foi efetivamente registrado, mas retorna false
137+ // quando o usuário é apenas atualizado
138+ function AddUser(const AInstagramUser: TInstagramUser; const AFollowingId: String = ''): Boolean; overload;
139+// function MediaInfo(AShortCode: String; out AMedia: TMedia): Boolean;
140+ procedure UpdateUser(const AInstagramUser: TInstagramUser); overload;
141+ procedure SelectFollowers(AUserId: String; AKRKDBGrid: TKRKDBGrid);
142+ procedure LikeLastMedia(const AKRKDBGridUser: TKRKDBGrid);
143+ procedure HandleModalResult(AInternalForm: TForm);
144+
145+ { Não revisadas }
146+ procedure UpdateCSRFToken(AHeaders: String);
147+ procedure UpdateHeaders(AHeaders: String);
148+ procedure UpdateRUR(AHeaders: String);
149+ procedure UpdateSessionId(AHeaders: String);
150+ procedure UpdateURLGen(AHeaders: String);
151+ { Revisados }
152+ public
153+ { Public declarations }
154+ { Lixo }
155+ FSessionId: String;
156+ FRUR: String;
157+ FURLGen: String;
158+ FCSRFToken: String;
159+ FSHBID: String;
160+ FSHBTS: String;
161+ FDSUserId: String;
162+ FMyID: String;
163+ FOtherId: String;
164+ FMyRealName: String;
165+ FOtherRealName: String;
166+ FNextPageAfter: String;
167+ FFollowingCounting: Cardinal;
168+ FFollowingPublicCounting: Cardinal;
169+ FFollowingPrivateCounting: Cardinal;
170+ FInstagramUsers: TInstagramUsers;
171+ FStopProcessing: Boolean;
172+ procedure ConfigureErrorHint(ATitle, AText: String; AWinControl: TWinControl; AShowHint: Boolean);
173+
174+ { Colocar como privado Revisadas }
175+ function Login(AUserName, APassword: String; out AInstagramUser: TInstagramUser): Boolean;
176+ function HeaderValue(AValue: String): String;
177+ function UserInfo(AUserName: String; var AInstagramUser: TInstagramUser): Boolean;
178+ procedure Wait; { isso é gambi }
179+ function LoggedUser(out AInstagramUser: TInstagramUser): Boolean;
180+ function LikeMedia(AMediaId: String; ALike: Boolean = True): Boolean;
181+
182+ { Colocar como privado não revisados }
183+ procedure GetFollowersPage(AUserId: String;
184+ var ANextPageToken: String;
185+ out AInstagramUsers: TInstagramUsers;
186+ out ATotalFollowers: Cardinal;
187+ AUsersPerPage: Byte = 50);
188+ function Logout: Boolean;
189+
190+ { Coisas revisadas }
191+ // Obtém os dados atualizados do usuário, atualizando também as últimas
192+ // mídias do mesmo!
193+ procedure UpdateUser(const AUserName: String); overload;
194+ procedure AddFollowers(const AUserId: String; AParams: TAddFollowersParams);
195+ procedure ConnectSQLite;
196+
197+ property WaitSeconds: Byte write FWaitSeconds;
198+ end;
199+
200+var
201+ DAMOPrincipal: TDAMOPrincipal;
202+
203+implementation
204+
205+uses
206+ KRK.Lib.Rtl.Win.WinInet.Utilities, Windows, WinInet,
207+ KRK.Lib.RegExp.Utils, NetEncoding, System.RegularExpressionsCore,
208+ UFORMPrincipal, jpeg, KRK.Lib.Vcl.Forms.FormBlender,
209+ UFORMStatus, UFORMAddUserParams;
210+
211+{%CLASSGROUP 'Vcl.Controls.TControl'}
212+
213+{$R *.dfm}
214+
215+function TDAMOPrincipal.AddUser(const AInstagramUser: TInstagramUser; const AFollowingId: String = ''): Boolean;
216+var
217+ ME: TMedia;
218+begin
219+ Result := FDCO.ExecSQLScalar('select count(id) from user where id = :id',[AInstagramUser.id],[ftString]) = 0;
220+
221+ FDTAUser.Append;
222+ FDTAUserid.AsString := AInstagramUser.id;
223+ FDTAUserusername.AsString := AInstagramUser.UserName;
224+ FDTAUserrealname.AsString := AInstagramUser.RealName;
225+ FDTAUserpictureurl.AsString := AInstagramUser.PictureURL;
226+ FDTAUserbiography.AsString := AInstagramUser.Biography;
227+ FDTAUserisprivate.AsBoolean := AInstagramUser.IsPrivate;
228+ FDTAUserisverified.AsBoolean := AInstagramUser.IsVerified;
229+ FDTAUserisbusinessaccount.AsBoolean := AInstagramUser.IsBusinessAccount;
230+ FDTAUserfollowers.AsInteger := AInstagramUser.Followers;
231+ FDTAUserfollowing.AsInteger := AInstagramUser.Following;
232+ FDTAUsermedias.AsInteger := AInstagramUser.MediasTotal;
233+ FDTAUser.Post;
234+
235+ if AFollowingId <> '' then
236+ begin
237+ FDTAFollowers.Append;
238+ FDTAFollowersfollowerid.AsString := AInstagramUser.id;
239+ FDTAFollowersfollowingid.AsString := AFollowingId;
240+ FDTAFollowers.Post;
241+ end;
242+
243+ for ME in AInstagramUser.LastestMedia do
244+ begin
245+ FDTAMedias.Append;
246+ FDTAMediasid.AsString := ME.Id;
247+ FDTAMediasshortcode.AsString := ME.ShortCode;
248+ FDTAMediaswidth.AsInteger := Me.Width;
249+ FDTAMediasheight.AsInteger := ME.Height;
250+ FDTAMediasuserid.AsString := AInstagramUser.id;
251+ FDTAMedias.Post;
252+ end;
253+end;
254+
255+procedure TDAMOPrincipal.ACTNAddUserExecute(Sender: TObject);
256+begin
257+ if Trim(FORMPrincipal.EDITProfile.Text) <> '' then
258+ begin
259+ AddUser(FORMPrincipal.EDITProfile.Text);
260+ LoadProfilePicture(FDTAUserid.AsString,FDTAUserpictureurl.AsString,FORMPrincipal.IMAGProfile);
261+ end
262+ else
263+ ConfigureErrorHint('Blank Field','Please inform the profile name to add',FORMPrincipal.EDITProfile,True);
264+end;
265+
266+procedure TDAMOPrincipal.ACTNLikeLastestExecute(Sender: TObject);
267+begin
268+ if FORMPrincipal.KRDGUser.SelectedRows.Count = 0 then
269+ ConfigureErrorHint('No user selected','Please select at least one user!',FORMPrincipal.KRDGUser,True)
270+ else
271+ LikeLastMedia(FORMPrincipal.KRDGUser);
272+end;
273+
274+procedure TDAMOPrincipal.ACTNSelectAllExecute(Sender: TObject);
275+var
276+ BM: TBookmark;
277+begin
278+ with FORMPrincipal.KRDGUser.DataSource.DataSet do
279+ begin
280+ DisableControls;
281+ BM := Bookmark;
282+ First;
283+ try
284+ while not EOF do
285+ begin
286+ FORMPrincipal.KRDGUser.SelectedRows.CurrentRowSelected := True;
287+ Next;
288+ end;
289+ finally
290+ Bookmark := BM;
291+ EnableControls;
292+ end;
293+ end;
294+ FORMPrincipal.UpdateUserSelectCount;
295+end;
296+
297+procedure TDAMOPrincipal.ACTNSelectFollowersExecute(Sender: TObject);
298+begin
299+ SelectFollowers(FDTAUserid.AsString,FORMPrincipal.KRDGUser);
300+ FORMPrincipal.UpdateUserSelectCount;
301+end;
302+
303+procedure TDAMOPrincipal.ACTNSelectInverseExecute(Sender: TObject);
304+var
305+ BM: TBookmark;
306+begin
307+ with FORMPrincipal.KRDGUser.DataSource.DataSet do
308+ begin
309+ DisableControls;
310+ BM := Bookmark;
311+ First;
312+ try
313+ while not EOF do
314+ begin
315+ FORMPrincipal.KRDGUser.SelectedRows.CurrentRowSelected := not FORMPrincipal.KRDGUser.SelectedRows.CurrentRowSelected;
316+ Next;
317+ end;
318+ finally
319+ Bookmark := BM;
320+ EnableControls;
321+ end;
322+ end;
323+ FORMPrincipal.UpdateUserSelectCount;
324+end;
325+
326+procedure TDAMOPrincipal.ACTNSelectNoneExecute(Sender: TObject);
327+begin
328+ FORMPrincipal.KRDGUser.SelectedRows.Clear;
329+ FORMPrincipal.UpdateUserSelectCount;
330+end;
331+
332+procedure TDAMOPrincipal.ACTNUpdateUserExecute(Sender: TObject);
333+begin
334+ if (FDTAUser.State = dsBrowse) and (FDTAUser.RecordCount > 0) then
335+ UpdateUser(FDTAUserusername.AsString);
336+end;
337+
338+procedure TDAMOPrincipal.AddUser(const AUserName: String; const AFollowingId: String = '');
339+var
340+ IU: TInstagramUser;
341+ FB: TKRKFormBlender;
342+ FS: TFORMStatus;
343+begin
344+ if not UserExists(AUserName) then
345+ begin
346+ TKRKFormBlender.ShowMe(FORMPrincipal,TFORMStatus,FB);
347+ try
348+ while not FB.InternalFormVisible do
349+ Application.ProcessMessages;
350+
351+ FS := TFORMStatus(FB.InternalFormInstance);
352+ FS.LABETitle.Caption := 'Adding user...';
353+ FS.LABEStatus.Caption := 'Please wait!';
354+ FS.BUTNCancel.Hide;
355+ FS.Update;
356+ // - /////////////////////////////////////////////////////////////////////
357+ if UserInfo(AUserName,IU) then
358+ AddUser(IU,AFollowingId);
359+ // - /////////////////////////////////////////////////////////////////////
360+ finally
361+ FB.Close;
362+ end;
363+ end
364+ else
365+ raise Exception.Create('User already exists!');
366+end;
367+
368+procedure TDAMOPrincipal.ConfigureErrorHint(ATitle, AText: String; AWinControl: TWinControl; AShowHint: Boolean);
369+begin
370+ with KRBH do
371+ begin
372+ AssociatedWinControl := AWinControl;
373+ TipTitle := ATitle;
374+ TipText := AText;
375+ MaxWidth := 320;
376+ TipIcon := tiError;
377+
378+ if AShowHint then
379+ Show;
380+ end;
381+end;
382+
383+procedure TDAMOPrincipal.ConnectSQLite;
384+begin
385+ FDCO.Connected := True;
386+ FDTAUser.Open;
387+ FDTAMedias.Open;
388+ FDTAFollowers.Open;
389+end;
390+
391+procedure TDAMOPrincipal.LoadProfilePicture(AUserId: String; APictureURL: String; AImage: TImage);
392+begin
393+ if not FileExists(ExtractFilePath(ParamStr(0)) + '\cache\' + AUserId + '.jpg') then
394+ DownloadProfilePicture(AUserId,APictureURL);
395+
396+ AImage.Picture.LoadFromFile(ExtractFilePath(ParamStr(0)) + '\cache\' + AUserId + '.jpg')
397+end;
398+procedure TDAMOPrincipal.DataModuleCreate(Sender: TObject);
399+begin
400+ FQueryHash := '56066f031e6239f35a904ac20c9f37d9';
401+ FWaitSeconds := 10;
402+ FRequestsSoFar := 0;
403+end;
404+
405+procedure TDAMOPrincipal.DoClearFlag(Sender: TField; var Text: string; DisplayText: Boolean);
406+begin
407+ Text := '';
408+end;
409+
410+procedure TDAMOPrincipal.DownloadProfilePicture(AUserId: String; APictureURL: String);
411+var
412+ RO: TRequestOptions;
413+ RE: TResponse;
414+// JI: TJPEGImage;
415+ IM: TImage;
416+begin
417+ ZeroMemory(@RO, SizeOf(RO));
418+ ZeroMemory(@RE, SizeOf(RE));
419+
420+ RO.AutoClearSSLState := True;
421+
422+ { InternetOpen }
423+ RO.InternetOpenParams.Agent := 'InstaLikes S2';
424+ RO.InternetOpenParams.AccessType := INTERNET_OPEN_TYPE_PRECONFIG;
425+ { InternetConnect }
426+ RO.InternetConnectParams.Service := INTERNET_SERVICE_HTTP;
427+ RO.InternetConnectParams.ServerName := PChar(APictureURL);
428+ { HttpOpenRequest }
429+ RO.HttpOpenRequestParams.Verb := 'GET';
430+ RO.HttpOpenRequestParams.ConnectTimeout := 30000;
431+ RO.HttpOpenRequestParams.SendTimeout := 30000;
432+ RO.HttpOpenRequestParams.ReceiveTimeout := 30000;
433+ RO.HttpOpenRequestParams.AcceptTypes := TStringList.Create;
434+ RO.HttpOpenRequestParams.AcceptTypes.Text := '*/*';
435+ RO.HttpOpenRequestParams.AutoDetectHTTPS := True;
436+ { HttpSendRequest }
437+ RO.HttpSendRequestParams.IgnoreInvalidCertificateCA := True;
438+ RE.Content := TStringStream.Create('');
439+ try
440+ Request(RO, RE);
441+ RE.Content.Seek(0, soFromBeginning);
442+
443+// JI := TJPEGImage.Create;
444+ try
445+// JI.LoadFromStream(RE.Content);
446+ IM := TImage.Create(nil);
447+ try
448+ IM.Picture.LoadFromStream(RE.Content);
449+
450+ if not DirectoryExists(ExtractFilePath(ParamStr(0)) + '\cache') then
451+ ForceDirectories(ExtractFilePath(ParamStr(0)) + '\cache');
452+
453+ IM.Picture.SaveToFile(ExtractFilePath(ParamStr(0)) + '\cache\' + AUserId + '.jpg');
454+ finally
455+ IM.Free;
456+ end;
457+ finally
458+// JI.Free;
459+ end;
460+ finally
461+ RE.Content.Free;
462+ RO.HttpOpenRequestParams.AcceptTypes.Free;
463+ RO.Content.Free;
464+ end;
465+end;
466+
467+procedure TDAMOPrincipal.Wait;
468+var
469+ NextTick: Cardinal;
470+begin
471+ NextTick := GetTickCount + FWaitSeconds * 1000;
472+ while (GetTickCount < NextTick) and (not FStopProcessing) do
473+ Application.ProcessMessages;
474+end;
475+
476+procedure TDAMOPrincipal.GetFollowersPage(AUserId: String; var ANextPageToken: String; out AInstagramUsers: TInstagramUsers; out ATotalFollowers: Cardinal; AUsersPerPage: Byte = 50);
477+var
478+ RO: TRequestOptions;
479+ RE: TResponse;
480+ JO: TJSONObject;
481+ Followers: TJSONArray;
482+ Follower: TJSONValue;
483+ Url: PChar;
484+begin
485+ SetLength(AInstagramUsers,0);
486+ ATotalFollowers := 0;
487+ ZeroMemory(@RO,SizeOf(RO));
488+ ZeroMemory(@RE,SizeOf(RE));
489+
490+ RO.AutoClearSSLState := True;
491+
492+ { InternetOpen }
493+ RO.InternetOpenParams.Agent := 'InstaLikes S2';
494+ RO.InternetOpenParams.AccessType := INTERNET_OPEN_TYPE_PRECONFIG;
495+
496+ { InternetConnect }
497+ RO.InternetConnectParams.Service := INTERNET_SERVICE_HTTP;
498+
499+ { HttpOpenRequest }
500+ RO.HttpOpenRequestParams.ConnectTimeout := 30000;
501+ RO.HttpOpenRequestParams.SendTimeout := 30000;
502+ RO.HttpOpenRequestParams.ReceiveTimeout := 30000;
503+ RO.HttpOpenRequestParams.AcceptTypes := TStringList.Create;
504+ RO.HttpOpenRequestParams.AcceptTypes.Text := '*/*';
505+ RO.HttpOpenRequestParams.AutoDetectHTTPS := True;
506+ RO.HttpOpenRequestParams.Headers := TStringList.Create;
507+
508+ { HttpSendRequest }
509+ RO.HttpSendRequestParams.IgnoreInvalidCertificateCA := True;
510+
511+ RE.Content := TStringStream.Create('');
512+ try
513+ if Trim(ANextPageToken) <> '' then
514+ Url := PChar('https://www.instagram.com/graphql/query/?query_hash=' + FQueryHash + '&variables=%7B%22id%22%3A%22' + AUserId + '%22%2C%22include_reel%22%3Afalse%2C%22fetch_mutual%22%3Afalse%2C%22first%22%3A' + AUsersPerPage.ToString + '%2C%22after%22%3A%22' + TNetEncoding.URL.Encode(ANextPageToken) + '%22%7D')
515+ else
516+ Url := PChar('https://www.instagram.com/graphql/query/?query_hash=' + FQueryHash + '&variables=%7B%22id%22%3A%22' + AUserId + '%22%2C%22include_reel%22%3Afalse%2C%22fetch_mutual%22%3Afalse%2C%22first%22%3A' + AUsersPerPage.ToString + '%7D');
517+
518+ ANextPageToken := '';
519+
520+ RO.InternetConnectParams.ServerName := Url;
521+
522+ RO.HttpOpenRequestParams.Verb := 'GET';
523+ RO.HttpOpenRequestParams.Headers.Add('sessionid: ' + HeaderValue(FSessionId));
524+// RO.HttpOpenRequestParams.Headers.Add('rur: ' + HeaderValue(FRUR));
525+// RO.HttpOpenRequestParams.Headers.Add('urlgen: ' + HeaderValue(FURLGen));
526+ RO.HttpOpenRequestParams.Headers.Add('x-csrftoken: ' + HeaderValue(FCSRFToken));
527+
528+ try
529+ Request(RO, RE);
530+ UpdateRequestsSoFar;
531+
532+ JO := TJSONObject.ParseJSONValue(TStringStream(RE.Content).DataString) as TJSONObject;
533+ try
534+ {"message": "rate limited", "status": "fail"}
535+ if not Assigned(JO.GetValue('data')) then // para testar com assigned, não use <TJSONObject>, pois imagino que isso tentaria gerar um cast de nil, caso o nó 'data' não exista
536+ begin
537+ if Assigned(JO.GetValue('message')) then
538+ raise Exception.Create('Não foi possível obter os dados: ' + JO.GetValue<String>('message'))
539+ else
540+ raise Exception.Create('Não foi possível obter os dados: Erro desconhecido')
541+ end;
542+
543+ Followers := JO.GetValue<TJSONObject>('data').
544+ GetValue<TJSONObject>('user').
545+ GetValue<TJSONObject>('edge_followed_by').
546+ GetValue<TJSONArray>('edges');
547+ ATotalFollowers := JO.GetValue<TJSONObject>('data').
548+ GetValue<TJSONObject>('user').
549+ GetValue<TJSONObject>('edge_followed_by').
550+ GetValue<Integer>('count');
551+
552+ if Followers.Count > 0 then
553+ begin
554+ if JO.GetValue<TJSONObject>('data').
555+ GetValue<TJSONObject>('user').
556+ GetValue<TJSONObject>('edge_followed_by').
557+ GetValue<TJSONObject>('page_info').
558+ GetValue<Boolean>('has_next_page') then
559+ ANextPageToken := JO.GetValue<TJSONObject>('data').
560+ GetValue<TJSONObject>('user').
561+ GetValue<TJSONObject>('edge_followed_by').
562+ GetValue<TJSONObject>('page_info').
563+ GetValue<String>('end_cursor');
564+
565+ for Follower in Followers do
566+ begin
567+ SetLength(AInstagramUsers,Length(AInstagramUsers) + 1);
568+
569+ AInstagramUsers[High(AInstagramUsers)].id := Follower.GetValue<TJSONObject>('node').
570+ GetValue<String>('id');
571+ AInstagramUsers[High(AInstagramUsers)].IsPrivate := Follower.GetValue<TJSONObject>('node').
572+ GetValue<Boolean>('is_private');
573+ AInstagramUsers[High(AInstagramUsers)].IsVerified := Follower.GetValue<TJSONObject>('node').
574+ GetValue<Boolean>('is_verified');
575+ AInstagramUsers[High(AInstagramUsers)].PictureURL := Follower.GetValue<TJSONObject>('node').
576+ GetValue<String>('profile_pic_url');
577+ AInstagramUsers[High(AInstagramUsers)].RealName := Follower.GetValue<TJSONObject>('node').
578+ GetValue<String>('full_name');
579+ AInstagramUsers[High(AInstagramUsers)].UserName := Follower.GetValue<TJSONObject>('node').
580+ GetValue<String>('username');
581+ AInstagramUsers[High(AInstagramUsers)].FollowedByViewer := Follower.GetValue<TJSONObject>('node').
582+ GetValue<Boolean>('followed_by_viewer');
583+ end;
584+
585+ UpdateHeaders(RE.Headers);
586+ end;
587+
588+ finally
589+ JO.Free;
590+ end;
591+ except
592+ on E: Exception do
593+ raise EInstagram.Create(E.Message);
594+ end;
595+ finally
596+ RE.Content.Free;
597+ RO.HttpOpenRequestParams.Headers.Free;
598+ RO.HttpOpenRequestParams.AcceptTypes.Free;
599+ RO.Content.Free;
600+ end;
601+end;
602+
603+procedure TDAMOPrincipal.HandleModalResult(AInternalForm: TForm);
604+begin
605+ FAddFollowersParams := TFORMAddUserParams(AInternalForm).AddFollowersParams;
606+end;
607+
608+function TDAMOPrincipal.HeaderValue(AValue: String): String;
609+begin
610+ Result := AValue;
611+ if Result = '' then
612+ Result := '""';
613+end;
614+
615+procedure TDAMOPrincipal.ACTNAddFollowersExecute(Sender: TObject);
616+begin
617+ if FDTAUser.RecordCount > 0 then
618+ if TKRKFormBlender.ShowMe(FORMPrincipal,TFORMAddUserParams,HandleModalResult) = mrOk then
619+ begin
620+ AddFollowers(FDTAUserid.AsString,FAddFollowersParams);
621+
622+ FDTAUser.Refresh;
623+ FDTAFollowers.Refresh;
624+ FDTAMedias.Refresh;
625+ end;
626+end;
627+
628+procedure TDAMOPrincipal.FDCOBeforeConnect(Sender: TObject);
629+begin
630+ FDCO.Params.Values['Database'] := ChangeFileExt(ParamStr(0),'.db');
631+end;
632+
633+procedure TDAMOPrincipal.FDTAUserAfterScroll(DataSet: TDataSet);
634+begin
635+ if (DataSet.State = dsBrowse) and (DataSet.RecordCount > 0) then
636+ LoadProfilePicture(FDTAUserid.AsString,FDTAUserpictureurl.AsString,FormPrincipal.IMAGProfile);
637+end;
638+
639+procedure TDAMOPrincipal.FDTAUserfollowersGetText(Sender: TField; var Text: string; DisplayText: Boolean);
640+begin
641+ if DisplayText then
642+ Text := 'Followers: ' + Sender.AsString
643+ else
644+ Text := Sender.AsString;
645+end;
646+
647+procedure TDAMOPrincipal.FDTAUserfollowingGetText(Sender: TField; var Text: string; DisplayText: Boolean);
648+begin
649+ if DisplayText then
650+ Text := 'Following: ' + Sender.AsString
651+ else
652+ Text := Sender.AsString;
653+end;
654+
655+procedure TDAMOPrincipal.FDTAUsermediasGetText(Sender: TField; var Text: string; DisplayText: Boolean);
656+begin
657+ if DisplayText then
658+ Text := 'Shared media: ' + Sender.AsString
659+ else
660+ Text := Sender.AsString;
661+end;
662+
663+procedure TDAMOPrincipal.AddFollowers(const AUserId: String; AParams: TAddFollowersParams);
664+var
665+ NPT: String;
666+ Followers: TInstagramUsers;
667+ RT: Cardinal;
668+ i: Byte;
669+ UseExtendedFilters: Boolean;
670+ FB: TKRKFormBlender;
671+ FS: TFORMStatus;
672+ Registered: Word;
673+ Page: Word;
674+begin
675+ UseExtendedFilters := (AParams.FollowersCount > 0) or (AParams.FollowingCount > 0) or AParams.IncludeBusinessAccount;
676+
677+ if AParams.UsersToRegister = 0 then
678+ raise EInstagram.Create('Por favor informe a quantidade de usuários a registrar');
679+
680+ TKRKFormBlender.ShowMe(FORMPrincipal,TFORMStatus,FB);
681+ try
682+ while not FB.InternalFormVisible do
683+ Application.ProcessMessages;
684+
685+ FS := TFORMStatus(FB.InternalFormInstance);
686+ FS.LABETitle.Caption := 'Getting followers...';
687+ FS.LABEStatus.Caption := 'Page 1 (0 / ' + AParams.UsersToRegister.ToString + ')';
688+ FS.Update;
689+
690+ // - ///////////////////////////////////////////////////////////////////////
691+ FStopProcessing := False;
692+ Registered := 0;
693+ Page := 1;
694+ repeat
695+ Wait;
696+ if FStopProcessing then
697+ Break;
698+
699+ // Obtém uma página de seguidores com 50 seguidores no máximo
700+ GetFollowersPage(AUserId,NPT,Followers,RT);
701+
702+ // Caso haja seguidores, faz algo
703+ if Length(Followers) > 0 then
704+ begin
705+ for i := 0 to Pred(Length(Followers)) do
706+ begin
707+ // Só adiciona quem não existe
708+ if FDTAUser.Locate('id',Followers[i].id,[]) then
709+ Continue;
710+
711+ // Se não for para incluir perfis privados e o perfil for privado, pula
712+ if (not AParams.IncludePrivate) and Followers[i].IsPrivate then
713+ Continue;
714+ // Se não for para incluir perfis verificados e o perfil for verificado, pula
715+ if (not AParams.IncludeVerified) and Followers[i].IsVerified then
716+ Continue;
717+ // Se não for para incluir perfis seguidos pelo visualizador e o perfil for seguido pelo visualizador, pula
718+ if (not AParams.IncludeFollowedByViewer) and Followers[i].FollowedByViewer then
719+ Continue;
720+
721+ // Verificando se as opções de consulta precisam de uma requisição
722+ // adicional para obtenção de mais dados sobre o usuário
723+ if UseExtendedFilters then
724+ begin
725+ UserInfo(Followers[i].UserName,Followers[i]);
726+
727+ // Se não for para incluir perfis empresariais e o perfil for empresarial, pula
728+ if (not AParams.IncludeBusinessAccount) and Followers[i].IsBusinessAccount then
729+ Continue;
730+
731+ if AParams.FollowingCount > 0 then
732+ case AParams.FollowingRelation of
733+ rMoreThan: begin
734+ // Se o número de seguidos precisar ser maior que o parâmetro, mas for menor, pula
735+ if Followers[i].Following < AParams.FollowingCount then
736+ Continue;
737+ end;
738+ rLessThan: begin
739+ // Se o número de seguidos precisar ser menor que o parâmetro, mas for maior, pula
740+ if Followers[i].Following > AParams.FollowingCount then
741+ Continue;
742+ end;
743+ end;
744+
745+ if AParams.FollowersCount > 0 then
746+ case AParams.FollowersRelation of
747+ rMoreThan: begin
748+ // Se o número de seguidores precisar ser maior que o parâmetro, mas for menor, pula
749+ if Followers[i].Followers < AParams.FollowersCount then
750+ Continue;
751+ end;
752+ rLessThan: begin
753+ // Se o número de seguidores precisar ser menor que o parâmetro, mas for maior, pula
754+ if Followers[i].Followers > AParams.FollowersCount then
755+ Continue;
756+ end;
757+ end;
758+ end;
759+
760+ if AddUser(Followers[i],AUserId) then
761+ begin
762+ Dec(AParams.UsersToRegister);
763+ Inc(Registered);
764+ FS.LABEStatus.Caption := 'Page ' + Page.ToString + ' (' + Registered.ToString + ' / ' + (AParams.UsersToRegister + Registered).ToString + ')'; // pra não ter que criar uma variável :p
765+ FS.Update;
766+ end;
767+
768+ if AParams.UsersToRegister = 0 then
769+ Break;
770+ end;
771+ end;
772+ Inc(Page);
773+ until (NPT = '') or (AParams.UsersToRegister = 0);
774+ // - ///////////////////////////////////////////////////////////////////////
775+ Application.MessageBox('Operation finalized!','Success!',MB_ICONINFORMATION);
776+ finally
777+ FB.Close;
778+ end;
779+end;
780+
781+function TDAMOPrincipal.UserExists(AUserName: String): Boolean;
782+begin
783+ // troque por um locate, já que sempre estamos dando refresh nos datasets
784+ Result := FDCO.ExecSQLScalar('select count(*) from user where username = :username',[AUserName],[ftString]) <> 0;
785+end;
786+
787+function TDAMOPrincipal.UserInfo(AUserName: String; var AInstagramUser: TInstagramUser): Boolean;
788+var
789+ RO: TRequestOptions;
790+ RE: TResponse;
791+ JS: String;
792+ JO: TJSONObject;
793+ JA: TJSONArray;
794+ i: Byte;
795+begin
796+ if Trim(AUserName) = '' then
797+ raise EInstagram.Create('Por favor, informe um nome de usuário do qual você quer obter as informações');
798+
799+ ZeroMemory(@AInstagramUser,SizeOf(TInstagramUser));
800+ ZeroMemory(@RO,SizeOf(RO));
801+ ZeroMemory(@RE,SizeOf(RE));
802+
803+ RO.AutoClearSSLState := True;
804+
805+ { InternetOpen }
806+ RO.InternetOpenParams.Agent := 'InstaLikes S2';
807+ RO.InternetOpenParams.AccessType := INTERNET_OPEN_TYPE_PRECONFIG;
808+
809+ { InternetConnect }
810+ RO.InternetConnectParams.ServerName := PChar('https://www.instagram.com/' + AUserName);
811+ RO.InternetConnectParams.Service := INTERNET_SERVICE_HTTP;
812+
813+ { HttpOpenRequest }
814+ RO.HttpOpenRequestParams.Verb := 'GET';
815+ RO.HttpOpenRequestParams.ConnectTimeout := 30000;
816+ RO.HttpOpenRequestParams.SendTimeout := 30000;
817+ RO.HttpOpenRequestParams.ReceiveTimeout := 30000;
818+ RO.HttpOpenRequestParams.AcceptTypes := TStringList.Create;
819+ RO.HttpOpenRequestParams.AcceptTypes.Text := '*/*';
820+ RO.HttpOpenRequestParams.AutoDetectHTTPS := True;
821+ RO.HttpOpenRequestParams.Headers := TStringList.Create;
822+ RO.HttpOpenRequestParams.Headers.Add('x-csrftoken: ' + HeaderValue(FCSRFToken));
823+ RO.HttpOpenRequestParams.Flags := INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_PRAGMA_NOCACHE;
824+
825+ { HttpSendRequest }
826+ RO.HttpSendRequestParams.IgnoreInvalidCertificateCA := True;
827+
828+ RE.Content := TStringStream.Create('');
829+ try
830+ try
831+ Request(RO, RE);
832+ UpdateRequestsSoFar;
833+
834+ // Aparentemente isso não é bom para detectar se a função como um todo
835+ // retorna true, pois o fato de haver este JSON pode não ser condição para
836+ // dados foram obtidos. As chamadas JSON ali adiante, podem levantar exceções
837+ // Mais do que nunca, crie uma exceção personalizada para resolver este problema
838+ // e escolha ao menos um atributo do JSON para indicar o sucesso desta função
839+ Result := RegExMatch(TStringStream(RE.Content).DataString,'window\._sharedData = ({.*})',1,1,False,[],JS);
840+
841+ if Result then
842+ begin
843+ JO := TJSONObject.ParseJSONValue(JS) as TJSONObject;
844+ try
845+ AInstagramUser.id := JO.GetValue('entry_data').
846+ GetValue<TJSONArray>('ProfilePage').Items[0].
847+ GetValue<TJSONObject>('graphql').
848+ GetValue<TJSONObject>('user').
849+ GetValue<String>('id');
850+ AInstagramUser.Biography := JO.GetValue('entry_data').
851+ GetValue<TJSONArray>('ProfilePage').Items[0].
852+ GetValue<TJSONObject>('graphql').
853+ GetValue<TJSONObject>('user').
854+ GetValue<String>('biography');
855+ AInstagramUser.IsPrivate := JO.GetValue('entry_data').
856+ GetValue<TJSONArray>('ProfilePage').Items[0].
857+ GetValue<TJSONObject>('graphql').
858+ GetValue<TJSONObject>('user').
859+ GetValue<Boolean>('is_private');
860+ AInstagramUser.IsVerified := JO.GetValue('entry_data').
861+ GetValue<TJSONArray>('ProfilePage').Items[0].
862+ GetValue<TJSONObject>('graphql').
863+ GetValue<TJSONObject>('user').
864+ GetValue<Boolean>('is_verified');
865+ AInstagramUser.PictureURL := JO.GetValue('entry_data').
866+ GetValue<TJSONArray>('ProfilePage').Items[0].
867+ GetValue<TJSONObject>('graphql').
868+ GetValue<TJSONObject>('user').
869+ GetValue<String>('profile_pic_url');
870+ AInstagramUser.RealName := JO.GetValue('entry_data').
871+ GetValue<TJSONArray>('ProfilePage').Items[0].
872+ GetValue<TJSONObject>('graphql').
873+ GetValue<TJSONObject>('user').
874+ GetValue<String>('full_name');
875+ AInstagramUser.UserName := JO.GetValue('entry_data').
876+ GetValue<TJSONArray>('ProfilePage').Items[0].
877+ GetValue<TJSONObject>('graphql').
878+ GetValue<TJSONObject>('user').
879+ GetValue<String>('username');
880+ AInstagramUser.FollowedByViewer := JO.GetValue('entry_data').
881+ GetValue<TJSONArray>('ProfilePage').Items[0].
882+ GetValue<TJSONObject>('graphql').
883+ GetValue<TJSONObject>('user').
884+ GetValue<Boolean>('followed_by_viewer');
885+ AInstagramUser.Followers := JO.GetValue('entry_data').
886+ GetValue<TJSONArray>('ProfilePage').Items[0].
887+ GetValue<TJSONObject>('graphql').
888+ GetValue<TJSONObject>('user').
889+ GetValue<TJSONObject>('edge_followed_by').
890+ GetValue<Cardinal>('count');
891+ AInstagramUser.Following := JO.GetValue('entry_data').
892+ GetValue<TJSONArray>('ProfilePage').Items[0].
893+ GetValue<TJSONObject>('graphql').
894+ GetValue<TJSONObject>('user').
895+ GetValue<TJSONObject>('edge_follow').
896+ GetValue<Cardinal>('count');
897+ AInstagramUser.IsBusinessAccount := JO.GetValue('entry_data').
898+ GetValue<TJSONArray>('ProfilePage').Items[0].
899+ GetValue<TJSONObject>('graphql').
900+ GetValue<TJSONObject>('user').
901+ GetValue<String>('is_business_account') = 'true';
902+ AInstagramUser.MediasTotal := JO.GetValue('entry_data').
903+ GetValue<TJSONArray>('ProfilePage').Items[0].
904+ GetValue<TJSONObject>('graphql').
905+ GetValue<TJSONObject>('user').
906+ GetValue<TJSONObject>('edge_owner_to_timeline_media').
907+ GetValue<Cardinal>('count');
908+
909+ JA := JO.GetValue('entry_data').
910+ GetValue<TJSONArray>('ProfilePage').Items[0].
911+ GetValue<TJSONObject>('graphql').
912+ GetValue<TJSONObject>('user').
913+ GetValue<TJSONObject>('edge_owner_to_timeline_media').
914+ GetValue<TJSONArray>('edges');
915+
916+ if JA.Count > 0 then
917+ begin
918+ SetLength(AInstagramUser.LastestMedia,JA.Count);
919+
920+ for i := 0 to Pred(JA.Count) do
921+ begin
922+ AInstagramUser.LastestMedia[i].id := JA.Items[i].GetValue<TJSONObject>('node').
923+ GetValue<String>('id');
924+ AInstagramUser.LastestMedia[i].Height := JA.Items[i].GetValue<TJSONObject>('node').
925+ GetValue<TJSONObject>('dimensions').
926+ GetValue<Cardinal>('height');
927+ AInstagramUser.LastestMedia[i].Width := JA.Items[i].GetValue<TJSONObject>('node').
928+ GetValue<TJSONObject>('dimensions').
929+ GetValue<Cardinal>('width');
930+ AInstagramUser.LastestMedia[i].ShortCode := JA.Items[i].GetValue<TJSONObject>('node').
931+ GetValue<String>('shortcode');
932+ end;
933+ end;
934+ finally
935+ JO.Free;
936+ end;
937+ end;
938+ except
939+ on E: Exception do
940+ raise EInstagram.Create(E.Message);
941+ end;
942+ finally
943+ RE.Content.Free;
944+ RO.HttpOpenRequestParams.Headers.Free;
945+ RO.HttpOpenRequestParams.AcceptTypes.Free;
946+ end;
947+end;
948+
949+procedure TDAMOPrincipal.UpdateCSRFToken(AHeaders: String);
950+var
951+ Value: String;
952+begin
953+ if RegExMatch(AHeaders,'csrftoken="?([^"]*)"?;',1,1,True,[preUnGreedy],Value) then
954+ FCSRFToken := Value;
955+end;
956+
957+procedure TDAMOPrincipal.UpdateHeaders(AHeaders: String);
958+begin
959+ UpdateSessionId(AHeaders);
960+ UpdateRUR(AHeaders);
961+ UpdateURLGen(AHeaders);
962+ UpdateCSRFToken(AHeaders);
963+end;
964+
965+procedure TDAMOPrincipal.UpdateRequestsSoFar;
966+begin
967+ Inc(FRequestsSoFar);
968+ FORMPrincipal.STBA.Panels[0].Text := FRequestsSoFar.ToString + ' requests so far...';
969+end;
970+
971+procedure TDAMOPrincipal.UpdateRUR(AHeaders: String);
972+var
973+ Value: String;
974+begin
975+ if RegExMatch(AHeaders,'rur="?([^"]*)"?;',1,1,True,[preUnGreedy],Value) then
976+ FRUR := Value;
977+end;
978+
979+procedure TDAMOPrincipal.UpdateSessionId(AHeaders: String);
980+var
981+ Value: String;
982+begin
983+ if RegExMatch(AHeaders,'sessionid="?([^"]*)"?;',1,1,True,[preUnGreedy],Value) then
984+ FSessionId := Value;
985+end;
986+
987+procedure TDAMOPrincipal.UpdateURLGen(AHeaders: String);
988+var
989+ Value: String;
990+begin
991+ if RegExMatch(AHeaders,'urlgen=(".*");',1,1,True,[preUnGreedy],Value) then
992+ FURLGen := Value;
993+end;
994+
995+procedure TDAMOPrincipal.UpdateUser(const AInstagramUser: TInstagramUser);
996+begin
997+ // Ao usar o AddUser para atualizar, o SQLite exclui o registro existete e
998+ // coloca outro no lugar e isso fazia a regra on delete cascade ser ativada.
999+ // Usando o pragma, desativa temporariamente as chaves estrangeiras evitando
1000+ // o problema
1001+ FDCO.ExecSQL('PRAGMA foreign_keys = 0;');
1002+ try
1003+ AddUser(AInstagramUser);
1004+ finally
1005+ FDCO.ExecSQL('PRAGMA foreign_keys = 1;');
1006+ end;
1007+end;
1008+
1009+procedure TDAMOPrincipal.UpdateUser(const AUserName: String);
1010+var
1011+ IU: TInstagramUser;
1012+begin
1013+ if UserExists(AUserName) then
1014+ begin
1015+ if UserInfo(AUserName,IU) then
1016+ begin
1017+ UpdateUser(IU);
1018+ DownloadProfilePicture(IU.id,IU.PictureURL);
1019+
1020+ FDTAUser.Refresh;
1021+ FDTAFollowers.Refresh;
1022+ FDTAMedias.Refresh;
1023+ end;
1024+ end
1025+ else
1026+ raise Exception.Create('User does not exist!');
1027+end;
1028+
1029+// Todas as chamadas que usam JSON sabem quem é o usuário que está executando a
1030+// ação, que é o usuário logado. O nó, config.viewer tem esta informação. A
1031+// função abaixo serve apenas para verificar de forma exclusiva esta informação
1032+function TDAMOPrincipal.LoggedUser(out AInstagramUser: TInstagramUser): Boolean;
1033+var
1034+ RO: TRequestOptions;
1035+ RE: TResponse;
1036+ JS: String;
1037+ JO: TJSONObject;
1038+begin
1039+ ZeroMemory(@AInstagramUser,SizeOf(TInstagramUser));
1040+ ZeroMemory(@RO,SizeOf(RO));
1041+ ZeroMemory(@RE,SizeOf(RE));
1042+
1043+ RO.AutoClearSSLState := True;
1044+
1045+ { InternetOpen }
1046+ RO.InternetOpenParams.Agent := 'InstaLikes S2';
1047+ RO.InternetOpenParams.AccessType := INTERNET_OPEN_TYPE_PRECONFIG;
1048+
1049+ { InternetConnect }
1050+ RO.InternetConnectParams.ServerName := 'https://www.instagram.com';
1051+ RO.InternetConnectParams.Service := INTERNET_SERVICE_HTTP;
1052+
1053+ { HttpOpenRequest }
1054+ RO.HttpOpenRequestParams.Verb := 'GET';
1055+ RO.HttpOpenRequestParams.ConnectTimeout := 30000;
1056+ RO.HttpOpenRequestParams.SendTimeout := 30000;
1057+ RO.HttpOpenRequestParams.ReceiveTimeout := 30000;
1058+ RO.HttpOpenRequestParams.AcceptTypes := TStringList.Create;
1059+ RO.HttpOpenRequestParams.AcceptTypes.Text := '*/*';
1060+ RO.HttpOpenRequestParams.AutoDetectHTTPS := True;
1061+ RO.HttpOpenRequestParams.Flags := INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_PRAGMA_NOCACHE;
1062+
1063+ { HttpSendRequest }
1064+ RO.HttpSendRequestParams.IgnoreInvalidCertificateCA := True;
1065+
1066+ RE.Content := TStringStream.Create('');
1067+ try
1068+ Request(RO, RE);
1069+ UpdateRequestsSoFar;
1070+ // Precisa UpdateHeaders porque esta função é usada ao iniciar o programa
1071+ // para pegar os cabeçalhos de quem estiver logado
1072+ UpdateHeaders(RE.Headers);
1073+
1074+ Result := RegExMatch(TStringStream(RE.Content).DataString,'window\._sharedData = ({.*})',1,1,False,[],JS);
1075+
1076+ if Result then
1077+ begin
1078+ JO := TJSONObject.ParseJSONValue(JS) as TJSONObject;
1079+ try
1080+ Result := not (JO.GetValue('config').GetValue<TJSONValue>('viewer') is TJSONNull);
1081+
1082+ if Result then
1083+ begin
1084+ AInstagramUser.id := JO.GetValue('config').
1085+ GetValue<TJSONObject>('viewer').
1086+ GetValue<String>('id');
1087+ AInstagramUser.IsPrivate := JO.GetValue('config').
1088+ GetValue<TJSONObject>('viewer').
1089+ GetValue<String>('is_private') = 'true';
1090+ AInstagramUser.PictureURL := JO.GetValue('config').
1091+ GetValue<TJSONObject>('viewer').
1092+ GetValue<String>('profile_pic_url');
1093+ AInstagramUser.RealName := JO.GetValue('config').
1094+ GetValue<TJSONObject>('viewer').
1095+ GetValue<String>('full_name');
1096+ AInstagramUser.UserName := JO.GetValue('config').
1097+ GetValue<TJSONObject>('viewer').
1098+ GetValue<String>('username');
1099+ AInstagramUser.Biography := JO.GetValue('config').
1100+ GetValue<TJSONObject>('viewer').
1101+ GetValue<String>('biography');
1102+ end;
1103+ finally
1104+ JO.Free;
1105+ end;
1106+ end;
1107+
1108+// UpdateHeaders(RE.Headers);
1109+// Result := RegExMatch(TStringStream(RE.Content).DataString,'"id":"(.*)"',1,1,True,[preUnGreedy],AId) and (AId <> '');
1110+//
1111+// if Result then
1112+// begin
1113+// RegExMatch(TStringStream(RE.Content).DataString,'"username":"(.*)"',1,1,True,[preUnGreedy],AUserName);
1114+// RegExMatch(TStringStream(RE.Content).DataString,'"full_name":"(.*)"',1,1,True,[preUnGreedy],ARealName);
1115+// RegExMatch(TStringStream(RE.Content).DataString,'"biography":"(.*)"',1,1,True,[preUnGreedy],ABiography);
1116+// RegExMatch(TStringStream(RE.Content).DataString,'"profile_pic_url":"(.*)"',1,1,True,[preUnGreedy],AProfilePicURL);
1117+// end;
1118+ finally
1119+ RE.Content.Free;
1120+// RO.HttpOpenRequestParams.Headers.Free;
1121+ RO.HttpOpenRequestParams.AcceptTypes.Free;
1122+ RO.Content.Free;
1123+ end;
1124+end;
1125+
1126+function TDAMOPrincipal.LikeMedia(AMediaId: String; ALike: Boolean = True): Boolean;
1127+var
1128+ RO: TRequestOptions;
1129+ RE: TResponse;
1130+begin
1131+ ZeroMemory(@RO,SizeOf(RO));
1132+ ZeroMemory(@RE,SizeOf(RE));
1133+
1134+ RO.AutoClearSSLState := True;
1135+ RO.Content := TStringStream.Create('1=1');// Satisfazendo o Krakatoa :)
1136+
1137+ { InternetOpen }
1138+ RO.InternetOpenParams.Agent := 'InstaLikes S2';
1139+ RO.InternetOpenParams.AccessType := INTERNET_OPEN_TYPE_PRECONFIG;
1140+
1141+ { InternetConnect }
1142+ if not ALike then
1143+ RO.InternetConnectParams.ServerName := PChar('https://www.instagram.com/web/likes/' + AMediaId + '/unlike/')
1144+ else
1145+ RO.InternetConnectParams.ServerName := PChar('https://www.instagram.com/web/likes/' + AMediaId + '/like/');
1146+
1147+ RO.InternetConnectParams.Service := INTERNET_SERVICE_HTTP;
1148+
1149+ { HttpOpenRequest }
1150+ RO.HttpOpenRequestParams.Verb := 'POST';
1151+ RO.HttpOpenRequestParams.ConnectTimeout := 30000;
1152+ RO.HttpOpenRequestParams.SendTimeout := 30000;
1153+ RO.HttpOpenRequestParams.ReceiveTimeout := 30000;
1154+ RO.HttpOpenRequestParams.AcceptTypes := TStringList.Create;
1155+ RO.HttpOpenRequestParams.AcceptTypes.Text := '*/*';
1156+ RO.HttpOpenRequestParams.AutoDetectHTTPS := True;
1157+ RO.HttpOpenRequestParams.Headers := TStringList.Create;
1158+// RO.HttpOpenRequestParams.Headers.Add('content-type: application/x-www-form-urlencoded');
1159+ RO.HttpOpenRequestParams.Headers.Add('x-csrftoken: ' + HeaderValue(FCSRFToken));
1160+ RO.HttpOpenRequestParams.Flags := INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_PRAGMA_NOCACHE;
1161+
1162+ { HttpSendRequest }
1163+ RO.HttpSendRequestParams.IgnoreInvalidCertificateCA := True;
1164+
1165+ RE.Content := TStringStream.Create('');
1166+ try
1167+ Request(RO, RE);
1168+ UpdateRequestsSoFar;
1169+
1170+ Result := TStringStream(RE.Content).DataString = '{"status": "ok"}';
1171+ finally
1172+ RE.Content.Free;
1173+ RO.HttpOpenRequestParams.Headers.Free;
1174+ RO.HttpOpenRequestParams.AcceptTypes.Free;
1175+ RO.Content.Free;
1176+ end;
1177+end;
1178+
1179+function TDAMOPrincipal.Login(AUserName: String; APassword: String; out AInstagramUser: TInstagramUser): Boolean;
1180+var
1181+ RO: TRequestOptions;
1182+ RE: TResponse;
1183+ JO: TJSONObject;
1184+begin
1185+ ZeroMemory(@AInstagramUser,SizeOf(TInstagramUser));
1186+ ZeroMemory(@RO,SizeOf(RO));
1187+ ZeroMemory(@RE,SizeOf(RE));
1188+
1189+ RO.AutoClearSSLState := True;
1190+
1191+ { InternetOpen }
1192+ RO.InternetOpenParams.Agent := 'InstaLikes S2';
1193+ RO.InternetOpenParams.AccessType := INTERNET_OPEN_TYPE_PRECONFIG;
1194+
1195+ { InternetConnect }
1196+ RO.InternetConnectParams.Service := INTERNET_SERVICE_HTTP;
1197+
1198+ { HttpOpenRequest }
1199+ RO.HttpOpenRequestParams.ConnectTimeout := 30000;
1200+ RO.HttpOpenRequestParams.SendTimeout := 30000;
1201+ RO.HttpOpenRequestParams.ReceiveTimeout := 30000;
1202+ RO.HttpOpenRequestParams.AcceptTypes := TStringList.Create;
1203+ RO.HttpOpenRequestParams.AcceptTypes.Text := '*/*';
1204+ RO.HttpOpenRequestParams.AutoDetectHTTPS := True;
1205+ RO.HttpOpenRequestParams.Headers := TStringList.Create;
1206+
1207+ { HttpSendRequest }
1208+ RO.HttpSendRequestParams.IgnoreInvalidCertificateCA := True;
1209+
1210+ RE.Content := TStringStream.Create('');
1211+ try
1212+ // Acessa a página inicial deslogado e obtém alguns headers
1213+ RO.InternetConnectParams.ServerName := 'https://www.instagram.com';
1214+ RO.HttpOpenRequestParams.Verb := 'GET';
1215+ Request(RO, RE);
1216+ UpdateRequestsSoFar;
1217+ UpdateHeaders(RE.Headers);
1218+ TStringStream(RE.Content).Clear;
1219+
1220+ // Acessa a página de login
1221+ RO.InternetConnectParams.ServerName := 'https://www.instagram.com/accounts/login/ajax/';
1222+ RO.HttpOpenRequestParams.Verb := 'POST';
1223+ RO.HttpOpenRequestParams.Headers.Add('Content-Type: application/x-www-form-urlencoded; charset=utf-8');
1224+// RO.HttpOpenRequestParams.Headers.Add('sessionid: ' + HeaderValue(FSessionId));
1225+// RO.HttpOpenRequestParams.Headers.Add('rur: ' + HeaderValue(FRUR));
1226+// RO.HttpOpenRequestParams.Headers.Add('urlgen: ' + HeaderValue(FURLGen));
1227+ RO.HttpOpenRequestParams.Headers.Add('x-csrftoken: ' + HeaderValue(FCSRFToken));
1228+ RO.Content := TStringStream.Create('username=' + AUserName +'&password=' + APassword + '&queryParams=%7B%7D');
1229+
1230+ Request(RO,RE);
1231+
1232+ (*
1233+ O resultado de um login bem sucedido é
1234+
1235+ {"authenticated": true, "user": true, "userId": "1355122894", "oneTapPrompt": false, "fr": "ASBX8CUusfR8ZedI3ByKovdcVXKVCbBUYAXaXAMqtuMdFO87yXixmQ0FLtK5LkkCz9AvlyfP5EIsEsADY1WTJqBaaEwuT0r0Asq2kVccC9NPVAZDKrGYGAXXbtZi1RmjI29uIQ", "reactivated": true, "status": "ok"}
1236+
1237+ user = true significa que o usuario informado existe
1238+ *)
1239+
1240+ JO := TJSONObject.ParseJSONValue(TStringStream(RE.Content).DataString) as TJSONObject;
1241+ try
1242+ Result := (not (JO.GetValue('authenticated') is TJSONNull)) and (JO.GetValue<String>('authenticated') = 'true');
1243+
1244+ if Result then
1245+ begin
1246+ UpdateHeaders(RE.Headers);
1247+
1248+ AInstagramUser.id := JO.GetValue<String>('userId');
1249+ end;
1250+ finally
1251+ JO.Free;
1252+ end;
1253+ finally
1254+ RE.Content.Free;
1255+ RO.HttpOpenRequestParams.Headers.Free;
1256+ RO.HttpOpenRequestParams.AcceptTypes.Free;
1257+ RO.Content.Free;
1258+ end;
1259+end;
1260+
1261+function TDAMOPrincipal.Logout: Boolean;
1262+var
1263+ RO: TRequestOptions;
1264+ RE: TResponse;
1265+ Dummy: TInstagramUser;
1266+begin
1267+ ZeroMemory(@RO,SizeOf(RO));
1268+ ZeroMemory(@RE,SizeOf(RE));
1269+
1270+ RO.AutoClearSSLState := True;
1271+ RO.Content := TStringStream.Create('csrfmiddlewaretoken=' + FCSRFToken);
1272+
1273+ { InternetOpen }
1274+ RO.InternetOpenParams.Agent := 'InstaLikes S2';
1275+ RO.InternetOpenParams.AccessType := INTERNET_OPEN_TYPE_PRECONFIG;
1276+
1277+ { InternetConnect }
1278+ RO.InternetConnectParams.ServerName := 'https://www.instagram.com/accounts/logout/';
1279+ RO.InternetConnectParams.Service := INTERNET_SERVICE_HTTP;
1280+
1281+ { HttpOpenRequest }
1282+ RO.HttpOpenRequestParams.Verb := 'POST';
1283+ RO.HttpOpenRequestParams.ConnectTimeout := 30000;
1284+ RO.HttpOpenRequestParams.SendTimeout := 30000;
1285+ RO.HttpOpenRequestParams.ReceiveTimeout := 30000;
1286+ RO.HttpOpenRequestParams.AcceptTypes := TStringList.Create;
1287+ RO.HttpOpenRequestParams.AcceptTypes.Text := '*/*';
1288+ RO.HttpOpenRequestParams.AutoDetectHTTPS := True;
1289+ RO.HttpOpenRequestParams.Headers := TStringList.Create;
1290+ RO.HttpOpenRequestParams.Headers.Add('content-type: application/x-www-form-urlencoded');
1291+ RO.HttpOpenRequestParams.Headers.Add('shbid: ' + HeaderValue(FSHBID));
1292+ RO.HttpOpenRequestParams.Headers.Add('shbts: ' + HeaderValue(FSHBTS));
1293+ RO.HttpOpenRequestParams.Headers.Add('rur: ' + HeaderValue(FRUR));
1294+ RO.HttpOpenRequestParams.Headers.Add('x-csrftoken: ' + HeaderValue(FCSRFToken)); { X- ??}
1295+ RO.HttpOpenRequestParams.Headers.Add('ds_user_id: ' + HeaderValue(FDSUserId));
1296+ RO.HttpOpenRequestParams.Headers.Add('sessionid: ' + HeaderValue(FSessionId));
1297+ RO.HttpOpenRequestParams.Headers.Add('urlgen: ' + HeaderValue(FURLGEN));
1298+
1299+ { HttpSendRequest }
1300+ RO.HttpSendRequestParams.IgnoreInvalidCertificateCA := True;
1301+
1302+ RE.Content := TStringStream.Create('');
1303+ try
1304+ Request(RO, RE);
1305+ UpdateRequestsSoFar;
1306+ UpdateHeaders(RE.Headers);
1307+ Result := not LoggedUser(Dummy);
1308+ finally
1309+ RE.Content.Free;
1310+ RO.HttpOpenRequestParams.Headers.Free;
1311+ RO.HttpOpenRequestParams.AcceptTypes.Free;
1312+ RO.Content.Free;
1313+ end;
1314+end;
1315+
1316+//function TDAMOPrincipal.MediaInfo(AShortCode: String; out AMedia: TMedia): Boolean;
1317+//var
1318+// RO: TRequestOptions;
1319+// RE: TResponse;
1320+// JS: String;
1321+// JO: TJSONObject;
1322+//begin
1323+// ZeroMemory(@AMedia,SizeOf(TMedia));
1324+// ZeroMemory(@RO,SizeOf(RO));
1325+// ZeroMemory(@RE,SizeOf(RE));
1326+//
1327+// RO.AutoClearSSLState := True;
1328+//
1329+// { InternetOpen }
1330+// RO.InternetOpenParams.Agent := 'InstaLikes S2';
1331+// RO.InternetOpenParams.AccessType := INTERNET_OPEN_TYPE_PRECONFIG;
1332+//
1333+// { InternetConnect }
1334+// RO.InternetConnectParams.ServerName := PChar('https://www.instagram.com/p/' + AShortCode);
1335+// RO.InternetConnectParams.Service := INTERNET_SERVICE_HTTP;
1336+//
1337+// { HttpOpenRequest }
1338+// RO.HttpOpenRequestParams.Verb := 'GET';
1339+// RO.HttpOpenRequestParams.ConnectTimeout := 30000;
1340+// RO.HttpOpenRequestParams.SendTimeout := 30000;
1341+// RO.HttpOpenRequestParams.ReceiveTimeout := 30000;
1342+// RO.HttpOpenRequestParams.AcceptTypes := TStringList.Create;
1343+// RO.HttpOpenRequestParams.AcceptTypes.Text := '*/*';
1344+// RO.HttpOpenRequestParams.AutoDetectHTTPS := True;
1345+// RO.HttpOpenRequestParams.Headers := TStringList.Create;
1346+// RO.HttpOpenRequestParams.Headers.Add('x-csrftoken: ' + HeaderValue(FCSRFToken));
1347+// RO.HttpOpenRequestParams.Flags := INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_PRAGMA_NOCACHE;
1348+//
1349+// { HttpSendRequest }
1350+// RO.HttpSendRequestParams.IgnoreInvalidCertificateCA := True;
1351+//
1352+// RE.Content := TStringStream.Create('');
1353+// try
1354+// Request(RO, RE);
1355+// UpdateRequestsSoFar;
1356+//
1357+// Result := RegExMatch(TStringStream(RE.Content).DataString,'window\._sharedData = ({.*})',1,1,False,[],JS);
1358+//
1359+// if Result then
1360+// begin
1361+// JO := TJSONObject.ParseJSONValue(JS) as TJSONObject;
1362+// try
1363+// AMedia.id := JO.GetValue('entry_data').
1364+// GetValue<TJSONArray>('PostPage').Items[0].
1365+// GetValue<TJSONObject>('graphql').
1366+// GetValue<TJSONObject>('shortcode_media').
1367+// GetValue<String>('id');
1368+// AMedia.Width := JO.GetValue('entry_data').
1369+// GetValue<TJSONArray>('PostPage').Items[0].
1370+// GetValue<TJSONObject>('graphql').
1371+// GetValue<TJSONObject>('shortcode_media').
1372+// GetValue<TJSONObject>('dimensions').
1373+// GetValue<Cardinal>('width');
1374+// AMedia.Height := JO.GetValue('entry_data').
1375+// GetValue<TJSONArray>('PostPage').Items[0].
1376+// GetValue<TJSONObject>('graphql').
1377+// GetValue<TJSONObject>('shortcode_media').
1378+// GetValue<TJSONObject>('dimensions').
1379+// GetValue<Cardinal>('height');
1380+// finally
1381+// JO.Free;
1382+// end;
1383+// end;
1384+// finally
1385+// RE.Content.Free;
1386+// RO.HttpOpenRequestParams.AcceptTypes.Free;
1387+// RO.HttpOpenRequestParams.Headers.Free;
1388+// end;
1389+//end;
1390+
1391+procedure TDAMOPrincipal.SelectFollowers(AUserId: String; AKRKDBGrid: TKRKDBGrid);
1392+var
1393+ BM: TBookmark;
1394+begin
1395+ AKRKDBGrid.SelectedRows.Clear;
1396+ BM := FDTAUser.Bookmark;
1397+ FDTAUser.DisableControls;
1398+ try
1399+ FDTAFollowers.First;
1400+ while not FDTAFollowers.Eof do
1401+ begin
1402+ if FDTAUser.Locate('id',FDTAFollowersfollowerid.AsString,[]) then
1403+ AKRKDBGrid.SelectedRows.CurrentRowSelected := True;
1404+ FDTAFollowers.Next;
1405+ end;
1406+ finally
1407+ FDTAUser.Bookmark := BM;
1408+ FDTAUser.EnableControls;
1409+ end;
1410+end;
1411+
1412+procedure TDAMOPrincipal.LikeLastMedia(const AKRKDBGridUser: TKRKDBGrid);
1413+var
1414+ BM: TBookmark;
1415+ FB: TKRKFormBlender;
1416+ FS: TFORMStatus;
1417+ Liked: Word;
1418+begin
1419+ TKRKFormBlender.ShowMe(TForm(AKRKDBGridUser.Owner),TFORMStatus,FB);
1420+ try
1421+ while not FB.InternalFormVisible do
1422+ Application.ProcessMessages;
1423+
1424+ FS := TFORMStatus(FB.InternalFormInstance);
1425+ FS.LABETitle.Caption := 'Liking medias...';
1426+ FS.LABEStatus.Caption := '0 / ' + AKRKDBGridUser.SelectedRows.Count.ToString;
1427+ FS.Update;
1428+ // - ///////////////////////////////////////////////////////////////////////
1429+ FStopProcessing := False;
1430+
1431+ with AKRKDBGridUser.DataSource.DataSet do
1432+ begin
1433+ // Não posso usar DisableControls porque isso desativa o relacionamento
1434+ // mestre detalhe e não posso usar BlockReadSize := 1 porque
1435+ // currentrowselected não funciona mais além de serem apresentados
1436+ // comportamenos estranhos no grid :/
1437+ BM := Bookmark;
1438+ try
1439+ Liked := 0;
1440+ First;
1441+ while not EOF do
1442+ begin
1443+ if AKRKDBGridUser.SelectedRows.CurrentRowSelected then
1444+ begin
1445+ if (FDTAMedias.RecordCount > 0) then
1446+ begin
1447+ FDTAMedias.First;
1448+
1449+ if not FDTAMediaswasliked.AsBoolean then
1450+ begin
1451+ Wait;
1452+
1453+ if FStopProcessing then
1454+ Break;
1455+
1456+ if LikeMedia(FDTAMediasid.AsString) then
1457+ begin
1458+ FDTAMedias.Edit;
1459+ FDTAMediaswasliked.AsBoolean := True;
1460+ FDTAMedias.Post;
1461+ end;
1462+ end;
1463+ end;
1464+
1465+ Inc(Liked);
1466+ FS.LABEStatus.Caption := Liked.ToString + ' / ' + AKRKDBGridUser.SelectedRows.Count.ToString;
1467+ FS.Update;
1468+ end;
1469+
1470+ Next;
1471+ end;
1472+ finally
1473+ Bookmark := BM;
1474+ end;
1475+ end;
1476+ // - ///////////////////////////////////////////////////////////////////////
1477+ Application.MessageBox('Operation finalized!','Success!',MB_ICONINFORMATION);
1478+ finally
1479+ FB.Close; { Action = caFree}
1480+ end;
1481+end;
1482+
1483+end.
--- trunk/src/UFORMAddUserParams.pas (nonexistent)
+++ trunk/src/UFORMAddUserParams.pas (revision 4)
@@ -0,0 +1,93 @@
1+unit UFORMAddUserParams;
2+
3+interface
4+
5+uses
6+ Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
7+ Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, UPngBitBtn, UDAMOPrincipal,
8+ Vcl.ExtCtrls;
9+
10+type
11+ TFORMAddUserParams = class(TForm)
12+ LABETitle: TLabel;
13+ PNGBOK: TPngBitBtn;
14+ PNGBCancel: TPngBitBtn;
15+ LAEDUsersToRegister: TLabeledEdit;
16+ GRBXExtended: TGroupBox;
17+ CHBXIncludeBusinessAcount: TCheckBox;
18+ CBBXFollowingRelation: TComboBox;
19+ CBBXFollowersRelation: TComboBox;
20+ EDITFollowingCount: TEdit;
21+ EDITFollowersCount: TEdit;
22+ LABEFollowingCount: TLabel;
23+ LABEFollowersCount: TLabel;
24+ CHBXIncludePrivate: TCheckBox;
25+ CHBXIncludeVerified: TCheckBox;
26+ CHBXIncludeFollowedByViewer: TCheckBox;
27+ BEVE1: TBevel;
28+ procedure PNGBOKClick(Sender: TObject);
29+ procedure FormCreate(Sender: TObject);
30+ private
31+ { Private declarations }
32+ FAddFollowersParams: TAddFollowersParams;
33+ public
34+ { Public declarations }
35+ property AddFollowersParams: TAddFollowersParams read FAddFollowersParams;
36+ end;
37+
38+implementation
39+
40+{$R *.dfm}
41+
42+procedure TFORMAddUserParams.FormCreate(Sender: TObject);
43+begin
44+ ZeroMemory(@FAddFollowersParams,SizeOf(TAddFollowersParams));
45+end;
46+
47+procedure TFORMAddUserParams.PNGBOKClick(Sender: TObject);
48+begin
49+ if Trim(LAEDUsersToRegister.Text) = '' then
50+ DAMOPrincipal.ConfigureErrorHint('Blank field','Please inform the amount of users to register',LAEDUsersToRegister,True)
51+ else if (Trim(LAEDUsersToRegister.Text).ToInteger = 0) or (Trim(LAEDUsersToRegister.Text).ToInteger < 0) then
52+ DAMOPrincipal.ConfigureErrorHint('Incorrect value','The value must be greater than or equal to 1',LAEDUsersToRegister,True)
53+ else if (Trim(EDITFollowersCount.Text) <> '') and (Trim(EDITFollowersCount.Text).ToInteger <= 0) then
54+ DAMOPrincipal.ConfigureErrorHint('Incorrect value','The value must be greater than or equal to 1',EDITFollowersCount,True)
55+ else if (Trim(EDITFollowingCount.Text) <> '') and (Trim(EDITFollowingCount.Text).ToInteger <= 0) then
56+ DAMOPrincipal.ConfigureErrorHint('Incorrect value','The value must be greater than or equal to 1',EDITFollowingCount,True)
57+ else
58+ begin
59+ FAddFollowersParams.UsersToRegister := StrToInt(LAEDUsersToRegister.Text);
60+ FAddFollowersParams.IncludeVerified := CHBXIncludeVerified.Checked;
61+ FAddFollowersParams.IncludePrivate := CHBXIncludePrivate.Checked;
62+ FAddFollowersParams.IncludeFollowedByViewer := CHBXIncludeFollowedByViewer.Checked;
63+
64+ // Extras
65+ FAddFollowersParams.FollowersCount := StrToIntDef(EDITFollowersCount.Text,0);
66+
67+ if CBBXFollowersRelation.ItemIndex = 0 then
68+ FAddFollowersParams.FollowersRelation := rMoreThan
69+ else
70+ FAddFollowersParams.FollowersRelation := rLessThan;
71+
72+ FAddFollowersParams.FollowingCount := StrToIntDef(EDITFollowingCount.Text,0);
73+
74+ if CBBXFollowingRelation.ItemIndex = 0 then
75+ FAddFollowersParams.FollowingRelation := rMoreThan
76+ else
77+ FAddFollowersParams.FollowingRelation := rLessThan;
78+
79+ FAddFollowersParams.IncludeBusinessAccount := CHBXIncludeBusinessAcount.Checked;
80+
81+ ModalResult := mrOk;
82+ end;
83+
84+
85+
86+
87+
88+// FollowingRelation: TRelation;
89+// FollowersRelation: TRelation;
90+
91+end;
92+
93+end.
--- trunk/src/UFORMPrincipal.pas (nonexistent)
+++ trunk/src/UFORMPrincipal.pas (revision 4)
@@ -0,0 +1,209 @@
1+unit UFORMPrincipal;
2+
3+interface
4+
5+uses
6+ Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
7+ Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.ExtCtrls,
8+ Vcl.Imaging.pngimage, System.ImageList, Vcl.ImgList, UPngImageList, Data.DB,
9+ Vcl.Grids, Vcl.DBGrids, KRK.Components.DataControls.DBGrid, Vcl.Buttons,
10+ UPngBitBtn, UPngSpeedButton, UDAMOPrincipal, Vcl.DBCtrls;
11+
12+type
13+ TFORMPrincipal = class(TForm)
14+ PACO1: TPageControl;
15+ TASHLogado: TTabSheet;
16+ LABEUserName: TLabel;
17+ LABERealName: TLabel;
18+ LABEId: TLabel;
19+ LABEBiography: TLabel;
20+ LABEProfilePicURL: TLabel;
21+ BUTNLogout: TButton;
22+ TASHAbout: TTabSheet;
23+ IMAGAbout: TImage;
24+ IMAGAbout2: TImage;
25+ TASHUser: TTabSheet;
26+ KRDGUser: TKRKDBGrid;
27+ GRBXUserData: TGroupBox;
28+ GRBXUserTools: TGroupBox;
29+ GRBXAddUser: TGroupBox;
30+ EDITProfile: TEdit;
31+ PNGSAddUser: TPngSpeedButton;
32+ LAEDWait: TLabeledEdit;
33+ DBMOBiography: TDBMemo;
34+ DBTXFollowers: TDBText;
35+ DBTXFollowing: TDBText;
36+ DBTXMedia: TDBText;
37+ STTE1: TStaticText;
38+ BUTNAtivarBanco: TButton;
39+ GRBXLocateUser: TGroupBox;
40+ EDITLocateUser: TEdit;
41+ IMAGProfile: TImage;
42+ STBA: TStatusBar;
43+ KRDGMedias: TKRKDBGrid;
44+ DBTXRealName: TDBText;
45+ PNGSUpdateUser: TPngSpeedButton;
46+ STBAUser: TStatusBar;
47+ PNGSSelectAll: TPngSpeedButton;
48+ PNGSSelectNone: TPngSpeedButton;
49+ PNGSSelectInverse: TPngSpeedButton;
50+ PNGSLikeAll: TPngSpeedButton;
51+ PNGSLikeLastest: TPngSpeedButton;
52+ STBAMedias: TStatusBar;
53+ PANLMedias: TPanel;
54+ LABE2: TLabel;
55+ TASHConfigurations: TTabSheet;
56+ LAEDUserName1: TLabeledEdit;
57+ LAEDPassword: TLabeledEdit;
58+ BUTNLogar: TButton;
59+ procedure BUTNLogarClick(Sender: TObject);
60+ procedure FormShow(Sender: TObject);
61+ procedure BUTNLogoutClick(Sender: TObject);
62+ procedure FormCreate(Sender: TObject);
63+ procedure FormDestroy(Sender: TObject);
64+ procedure KRDGUserDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
65+ procedure EDITProfileKeyPress(Sender: TObject; var Key: Char);
66+ procedure LocateUser(Sender: TObject);
67+ procedure KRDGUserAfterMultiselect(aSender: TObject; aMultiSelectEventTrigger: TMultiSelectEventTrigger);
68+ procedure KRDGMediasDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
69+ procedure LAEDWaitChange(Sender: TObject);
70+ private
71+ { Private declarations }
72+ public
73+ { Public declarations }
74+ procedure UpdateUserSelectCount;
75+ end;
76+
77+var
78+ FORMPrincipal: TFORMPrincipal;
79+
80+implementation
81+
82+uses
83+ KRK.Lib.Rtl.Win.WinInet.Utilities, Winapi.WinInet, JSON, NetEncoding, CommCtrl;
84+
85+{$R *.dfm}
86+
87+{ TForm1 }
88+
89+procedure TFORMPrincipal.EDITProfileKeyPress(Sender: TObject; var Key: Char);
90+begin
91+ if Key = #13 then
92+ PNGSAddUser.Click;
93+end;
94+
95+procedure TFORMPrincipal.BUTNLogarClick(Sender: TObject);
96+var
97+ UI: TInstagramUser;
98+begin
99+ TASHLogado.TabVisible := DAMOPrincipal.Login(LAEDUserName1.Text,LAEDPassword.Text, UI);
100+
101+ if TASHLogado.TabVisible then
102+ begin
103+ DAMOPrincipal.UserInfo(LAEDUserName1.Text,UI);
104+ DAMOPrincipal.FMyId := UI.id;
105+ DAMOPrincipal.FMyRealName := UI.RealName;
106+ LABEId.Caption := DAMOPrincipal.FMyID;
107+ LABEUserName.Caption := UI.UserName;
108+ LABERealName.Caption := DAMOPrincipal.FMyRealName;
109+ LABEBiography.Caption := UI.Biography;
110+ LABEProfilePicURL.Caption := UI.PictureURL;
111+ end;
112+end;
113+
114+procedure TFORMPrincipal.BUTNLogoutClick(Sender: TObject);
115+begin
116+ TASHLogado.TabVisible := DAMOPrincipal.Logout;
117+
118+ if TASHLogado.TabVisible then
119+ Application.MessageBox('Não foi possível deslogar','Algo errado não está certo',MB_ICONERROR);
120+end;
121+
122+procedure TFORMPrincipal.FormCreate(Sender: TObject);
123+begin
124+ DAMOPrincipal.WaitSeconds := StrToInt(LAEDWait.Text);
125+ DAMOPrincipal.ConnectSQLite;
126+end;
127+
128+procedure TFORMPrincipal.FormDestroy(Sender: TObject);
129+begin
130+ DAMOPrincipal.FDCO.Connected := False;
131+end;
132+
133+procedure TFORMPrincipal.FormShow(Sender: TObject);
134+var
135+ IU: TInstagramUser;
136+begin
137+ TASHLogado.TabVisible := DAMOPrincipal.LoggedUser(IU);
138+
139+ if TASHLogado.TabVisible then
140+ begin
141+ DAMOPrincipal.FMyID := IU.id;
142+ DAMOPrincipal.FMyRealName := IU.RealName;
143+ LABEId.Caption := DAMOPrincipal.FMyID;
144+ LABEUserName.Caption := IU.UserName;
145+ LABERealName.Caption := DAMOPrincipal.FMyRealName;
146+ LABEBiography.Caption := IU.Biography;
147+ LABEProfilePicURL.Caption := Iu.PictureURL;
148+ end;
149+end;
150+
151+procedure TFORMPrincipal.KRDGMediasDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
152+var
153+ OffsetLeft: Byte;
154+begin
155+ inherited;
156+ if Column.FieldName = 'wasliked' then
157+ begin
158+ OffsetLeft := ((Rect.Right - Rect.Left) div 2) - 8;
159+
160+ if Column.Field.AsBoolean then
161+ DAMOPrincipal.PNIL2.Draw(TKRKDBGrid(Sender).Canvas
162+ ,Rect.Left + OffsetLeft
163+ ,Rect.Top
164+ ,1);
165+ end;
166+end;
167+
168+procedure TFORMPrincipal.KRDGUserAfterMultiselect(aSender: TObject; aMultiSelectEventTrigger: TMultiSelectEventTrigger);
169+begin
170+ UpdateUserSelectCount;
171+end;
172+
173+procedure TFORMPrincipal.KRDGUserDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
174+var
175+ OffsetLeft: Byte;
176+begin
177+ inherited;
178+ if (Column.FieldName = 'isprivate')
179+ or (Column.FieldName = 'isverified')
180+ or (Column.FieldName = 'isbusinessaccount')
181+ then
182+ begin
183+ OffsetLeft := ((Rect.Right - Rect.Left) div 2) - 8;
184+
185+ if Column.Field.AsBoolean then
186+ DAMOPrincipal.PNIL2.Draw(TKRKDBGrid(Sender).Canvas
187+ ,Rect.Left + OffsetLeft
188+ ,Rect.Top
189+ ,0);
190+ end;
191+end;
192+
193+procedure TFORMPrincipal.LAEDWaitChange(Sender: TObject);
194+begin
195+ if Trim(LAEDWait.Text) <> '' then
196+ DAMOPrincipal.WaitSeconds := StrToInt(LAEDWait.Text);
197+end;
198+
199+procedure TFORMPrincipal.LocateUser(Sender: TObject);
200+begin
201+ DAMOPrincipal.FDTAUser.Locate('username',EDITLocateUser.Text,[loPartialKey,loCaseInsensitive]);
202+end;
203+
204+procedure TFORMPrincipal.UpdateUserSelectCount;
205+begin
206+ STBAUser.Panels[0].Text := 'Selected: ' + KRDGUser.SelectedRows.Count.ToString;
207+end;
208+
209+end.
--- trunk/src/UFORMStatus.pas (nonexistent)
+++ trunk/src/UFORMStatus.pas (revision 4)
@@ -0,0 +1,24 @@
1+unit UFORMStatus;
2+
3+interface
4+
5+uses
6+ Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
7+ Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
8+
9+type
10+ TFORMStatus = class(TForm)
11+ LABEStatus: TLabel;
12+ BUTNCancel: TButton;
13+ LABETitle: TLabel;
14+ private
15+ { Private declarations }
16+ public
17+ { Public declarations }
18+ end;
19+
20+implementation
21+
22+{$R *.dfm}
23+
24+end.
Show on old repository browser