unit fSettings; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, uQ, FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls, ShellAPI, System.IOUtils, uDataBase, FMX.Controls.Presentation, FMX.Edit, uTWAuth, uRecords, uAPIDA, uShowText, json, uWSDA, fLog; type TfrSettings = class(TFrame) GroupBox3: TGroupBox; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label22: TLabel; edtBotName: TEdit; edtBotToken: TEdit; edtChannel: TEdit; btnGetToken: TButton; edtBotClientID: TEdit; btnGetClientID: TButton; btnOpenStream: TButton; btnGetTokenStreamer: TButton; edtBotTokenStreamer: TEdit; Label53: TLabel; GroupBox22: TGroupBox; btnDAGetCode: TButton; Label63: TLabel; edtDAClientID: TEdit; Label64: TLabel; edtDAClientSecret: TEdit; Label65: TLabel; edtDARedirectURL: TEdit; edtDACode: TEdit; Label66: TLabel; btnDAStart: TButton; btnGetDADef: TButton; cbDAAutoLogin: TCheckBox; cbTTVAutoLogin: TCheckBox; btnOpenRomaning: TButton; btnImportSettings: TButton; btnExportSettings: TButton; btnMaster: TButton; SaveDialog1: TSaveDialog; OpenDialog1: TOpenDialog; procedure btnGetTokenClick(Sender: TObject); procedure btnGetTokenStreamerClick(Sender: TObject); procedure btnOpenStreamClick(Sender: TObject); procedure btnDAGetCodeClick(Sender: TObject); procedure btnDAStartClick(Sender: TObject); procedure btnOpenRomaningClick(Sender: TObject); procedure btnImportSettingsClick(Sender: TObject); procedure btnExportSettingsClick(Sender: TObject); procedure btnMasterClick(Sender: TObject); private { Private declarations } FAPIClient: TAPIClient; forbot: boolean; procedure OnTTWToken(txt: string); procedure OnTokenDA(txt: string); procedure HandleWSStatus(AStatusText: string; AStatusCode: integer); procedure HandleWSDonate(aNick, aMessage, aSum: string); public { Public declarations } FWSClient: TWSClient; destructor Destroy; override; procedure init(); end; implementation {$R *.fmx} uses uGeneral; procedure TfrSettings.btnDAGetCodeClick(Sender: TObject); var twa: TTTWAuth; Url: string; begin if (edtDAClientSecret.text = '') or (edtDAClientID.text = '') or (edtDARedirectURL.text = '') then exit; Url := 'https://www.donationalerts.com/oauth/authorize?client_id=' + edtDAClientID.text + '&redirect_uri=http://localhost/da&response_type=code&scope=oauth-user-show+oauth-donation-subscribe'; twa := TTTWAuth.Create; twa.OnToken := OnTokenDA; twa.StartServer(Url); // ttw_Auth будет освобожден автоматически после получения токена (см. uTWAuth) end; procedure TfrSettings.OnTokenDA(txt: string); begin edtDACode.text := txt; if cbDAAutoLogin.IsChecked then begin btnDAStartClick(self); end; end; procedure TfrSettings.btnDAStartClick(Sender: TObject); var UserInfo: TJSONObject; Data: TJSONObject; begin if btnDAStart.text = 'Подключиться' then begin UserInfo := nil; try try if not Assigned(FAPIClient) then init; if FAPIClient.Token = '' then begin try FAPIClient.Token := FAPIClient.GetAccessToken( edtDAClientID.text, edtDAClientSecret.text, edtDARedirectURL.text, edtDACode.text ); except on E: Exception do begin TTW_Bot.toLog('fSettings', 'btnDAStartClick', 'Ошибка получения токена: ' + E.Message,2); Exit; end; end; FWSClient.APIClient := FAPIClient; try UserInfo := FAPIClient.GetUserInfo; Data := UserInfo.GetValue('data'); FWSClient.Wsstoken := Data.GetValue('socket_connection_token'); FWSClient.WSID := Data.GetValue('id'); except on E: Exception do begin TTW_Bot.toLog( 'fSettings','btnDAStartClick', 'Ошибка получения UserInfo: ' + E.Message,2); Exit; end; end; end; try FWSClient.Connect('wss://centrifugo.donationalerts.com/connection/websocket'); FWSClient.Send(Format( '{"params":{"token":"%s"},"id":1}', [FWSClient.Wsstoken] )); except on E: Exception do TTW_Bot.toLog( 'fSettings','btnDAStartClick', 'Ошибка подключения к WebSocket: ' + E.Message,2); end; except on E: Exception do TTW_Bot.toLog('fSettings', 'btnDAStartClick', 'Неизвестная ошибка: ' + E.Message,2); end; finally UserInfo.Free; end; end else begin try edtDACode.Text:=''; if Assigned(FWSClient) then begin try FWSClient.Disconnect; except on E: Exception do TTW_Bot.toLog( 'fSettings', 'btnDAStartClick', 'Ошибка при отключении WS: ' + E.Message,2); end; FreeAndNil(FWSClient); end; FreeAndNil(FAPIClient); finally btnDAStart.ImageIndex := 18; btnDAStart.text := 'Подключиться'; end; end; end; procedure TfrSettings.btnExportSettingsClick(Sender: TObject); var DestinationFile: string; begin SaveDialog1.FileName := TPath.GetFileName(myConst.DBPath); if SaveDialog1.Execute then begin DestinationFile := SaveDialog1.FileName; TFile.Copy(myConst.DBPath, DestinationFile, True); end; end; procedure TfrSettings.btnGetTokenClick(Sender: TObject); var s: string; sope: string; ttw_Auth: TTTWAuth; begin ttw_Auth := TTTWAuth.Create; ttw_Auth.OnToken := OnTTWToken; // ttw_Auth будет освобожден автоматически после получения токена (см. uTWAuth) sope := 'moderator:manage:shoutouts' + '+moderator:manage:announcements' + '+moderator:manage:banned_users' + '+moderator:manage:warnings' + '+moderator:read:followers' + '+channel:manage:raids' + '+channel:manage:moderators' + '+channel:read:redemptions' + '+chat:read' + '+chat:edit+user:read:emotes'; sope := StringReplace(sope, ':', '%3A', [rfReplaceAll]); s := 'https://id.twitch.tv/oauth2/authorize?client_id=' + edtBotClientID.text + '&redirect_uri=http://localhost&response_type=token&' + 'scope=' + sope; ttw_Auth.StartServer(''); forbot := True; fShowText.Memo1.Lines.text := s; fShowText.Show; fShowText.Memo1.WordWrap := True; end; procedure TfrSettings.btnGetTokenStreamerClick(Sender: TObject); var sope: string; ttw_Auth: TTTWAuth; begin ttw_Auth := TTTWAuth.Create; ttw_Auth.OnToken := OnTTWToken; sope := 'channel:read:redemptions' + '+channel:manage:vips' + '+moderator:read:followers' + '+channel:read:subscriptions' + '+channel:manage:moderators' + '+channel:manage:redemptions'; sope := StringReplace(sope, ':', '%3A', [rfReplaceAll]); ttw_Auth.StartServer('https://id.twitch.tv/oauth2/authorize?client_id=' + edtBotClientID.text + '&redirect_uri=http://localhost&response_type=token&' + 'scope=' + sope); forbot := false; end; procedure TfrSettings.btnImportSettingsClick(Sender: TObject); var SourceFile, DestinationDir, DestinationFile: string; begin if OpenDialog1.Execute then begin DB.Free; SourceFile := OpenDialog1.FileName; DestinationDir := myConst.DBPath; DestinationFile := myConst.DBPath; TFile.Copy(SourceFile, DestinationFile, True); DB := TSettingsDatabase.Create(myConst.DBPath); end; end; procedure TfrSettings.btnMasterClick(Sender: TObject); var qf: tfrmq; begin qf := tfrmq.Create(nil); try qf.SetLabelText('Введите ник аккаунта от которого будет писать бот:'); if qf.ShowModal = mrOk then edtBotName.text := qf.GetEditText; qf.SetLabelText('Введите ник стримера где будет работать бот:'); if qf.ShowModal = mrOk then edtChannel.text := qf.GetEditText; if btnGetClientID.Visible then begin edtBotClientID.text := appconst.TTV_ClientID; showmessage('Появится окно, там будет ссылка. ' + #13 + 'Скопируй ее и открой в браузере где авторизован бот. ' + #13 + 'Если понял - жми ОК'); btnGetTokenClick(self); showmessage ('Когда ссылка пропадет жми "Получить Token" около поля "API Token Стримера". ' + #13 + 'Если понял - жми ОК'); end else begin showmessage('Нет файла ключей! ' + #13 + 'Введите ClientID вручную и продолжите настройку без мастера!'); end; finally qf.Free; end; end; procedure TfrSettings.btnOpenRomaningClick(Sender: TObject); begin ShellExecute(0, 'open', pwidechar(ExtractFilePath(myConst.DBPath)), nil, nil, 1); end; procedure TfrSettings.btnOpenStreamClick(Sender: TObject); begin ShellExecute(0, 'open', pwidechar('https://www.twitch.tv/' + edtChannel.text), nil, nil, 1); end; destructor TfrSettings.Destroy; begin if Assigned(FWSClient) then begin try FWSClient.Disconnect; // если есть метод отключения except end; FreeAndNil(FWSClient); end; FreeAndNil(FAPIClient); inherited; end; procedure TfrSettings.init; begin if not Assigned(FAPIClient) then FAPIClient := TAPIClient.Create; if not Assigned(FWSClient) then begin FWSClient := TWSClient.Create; FWSClient.OnStatus := HandleWSStatus; FWSClient.OnDonate := HandleWSDonate; FWSClient.OnLog := TTW_Bot.toLog; end; end; procedure TfrSettings.OnTTWToken(txt: string); begin fShowText.Close; if forbot then begin edtBotToken.text := txt; DB.WriteSetting('edtBotToken', txt); end else begin edtBotTokenStreamer.text := txt; DB.WriteSetting('edtBotTokenStreamer', txt); end; end; procedure TfrSettings.HandleWSDonate(aNick, aMessage, aSum: string); begin // fDonats.OnDADonate(aNick, aMessage, aSum); end; procedure TfrSettings.HandleWSStatus(AStatusText: string; AStatusCode: integer); begin // fLog.tolog(3,'uLogin','HandleWSStatus',AStatusText); TTW_Bot.Label8.text := AStatusText; case AStatusCode of 0: begin btnDAStart.ImageIndex := 1; btnDAStart.text := 'Отключиться'; end; else begin btnDAStart.ImageIndex := 18; btnDAStart.text := 'Подключиться'; end; end; end; end.