From d7bf17daa2f2cdb37ffa8d5621a1483d0c82bdab Mon Sep 17 00:00:00 2001 From: "PC1\\PTyTb" Date: Sun, 17 Aug 2025 00:39:58 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BE=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Services/uCustomEmoties.pas | 6 +- Services/uKandinskyAPI.pas | 35 ++- Services/uTTWEventSub.pas | 410 +++++++++++++++++----------------- forms/uGeneral.pas | 30 +-- utils/uPlayerThread.pas | 2 +- utils/uWebServerEvents.pas | 4 +- utils/uWebServerKandinsky.pas | 2 +- 7 files changed, 260 insertions(+), 229 deletions(-) diff --git a/Services/uCustomEmoties.pas b/Services/uCustomEmoties.pas index d3079a0..fbfecff 100644 --- a/Services/uCustomEmoties.pas +++ b/Services/uCustomEmoties.pas @@ -189,8 +189,9 @@ var ssl: TIdSSLIOHandlerSocketOpenSSL; begin Result := ''; - http := TIdHTTP.Create(nil); + try + http := TIdHTTP.Create(nil); ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil); try http.IOHandler := ssl; @@ -200,6 +201,7 @@ begin Result := http.Get('https://api.betterttv.net/3/cached/' + aMethod); finally ssl.Free; + http.Free; end; except on E: Exception do @@ -208,7 +210,7 @@ begin Result := ''; end; end; - http.Free; + end; procedure TBTTV.toLog(alevel: integer; amethod, amessage: string); diff --git a/Services/uKandinskyAPI.pas b/Services/uKandinskyAPI.pas index 7b8db08..57b0417 100644 --- a/Services/uKandinskyAPI.pas +++ b/Services/uKandinskyAPI.pas @@ -50,9 +50,7 @@ begin FClient := THTTPClient.Create; FBaseURL := 'https://api-key.fusionbrain.ai/'; FApiKey :=aKey; - // FApiKey := '28C9C30489D635732FB04AA6B85F0671'; FSecretKey := aSecret; - // FSecretKey := '805CB624C052202A05E3F40C0582045A'; end; destructor TFusionBrainAPI.Destroy; @@ -62,8 +60,10 @@ begin end; procedure TFusionBrainAPI.StartGeneration(const APrompt: string); +var + Task: ITask; begin - TTask.Run(procedure + Task :=TTask.Run(procedure var PipelineID, UUID, FileName: string; Links: TArray; @@ -94,6 +94,7 @@ begin SetLength(Result, 2); Result[0] := TNetHeader.Create('X-Key', 'Key ' + FApiKey); Result[1] := TNetHeader.Create('X-Secret', 'Secret ' + FSecretKey); + end; function TFusionBrainAPI.GetPipeline: string; @@ -117,11 +118,11 @@ var Response: IHTTPResponse; Json: TJSONObject; begin + // Упрощенное создание JSON + Params := TJSONObject.Create; Root := TJSONObject.Create; try - Params := TJSONObject.Create; Params.AddPair('query', Prompt); - Root.AddPair('type', 'GENERATE'); Root.AddPair('numImages', TJSONNumber.Create(1)); Root.AddPair('width', TJSONNumber.Create(512)); @@ -145,22 +146,31 @@ begin end; finally Root.Free; + // Params освобождается автоматически через Root end; end; function TFusionBrainAPI.CheckGeneration(const RequestId: string): TArray; +const + MaxAttempts = 60; var Response: IHTTPResponse; Json, ResultObj: TJSONObject; Files: TJSONArray; - i: Integer; + i, Attempt: Integer; + Status: string; begin - repeat + Attempt := 0; + while Attempt < MaxAttempts do + begin Sleep(5000); + Inc(Attempt); + Response := FClient.Get(FBaseURL + 'key/api/v1/pipeline/status/' + RequestId, nil, GetAuthHeaders); Json := TJSONObject.ParseJSONValue(Response.ContentAsString) as TJSONObject; try - if Json.GetValue('status') = 'DONE' then + Status := Json.GetValue('status'); + if Status = 'DONE' then begin ResultObj := Json.GetValue('result'); Files := ResultObj.GetValue('files'); @@ -168,11 +178,14 @@ begin for i := 0 to Files.Count - 1 do Result[i] := Files.Items[i].Value; Exit; - end; + end + else if Status = 'FAILED' then + raise Exception.Create('Generation failed'); finally Json.Free; end; - until False; + end; + raise Exception.Create('Timeout waiting for generation'); end; procedure TFusionBrainAPI.SaveBase64Image(const Base64Str, FileName: string); @@ -181,7 +194,7 @@ var InputStr: TStringStream; begin DecodedStream := TMemoryStream.Create; - InputStr := TStringStream.Create(Base64Str); + InputStr := TStringStream.Create(Base64Str, TEncoding.ASCII); try TNetEncoding.Base64.Decode(InputStr, DecodedStream); DecodedStream.SaveToFile(FileName); diff --git a/Services/uTTWEventSub.pas b/Services/uTTWEventSub.pas index f59a516..8e0b5a5 100644 --- a/Services/uTTWEventSub.pas +++ b/Services/uTTWEventSub.pas @@ -15,10 +15,11 @@ type TGetGiftEvent = procedure(s: TGiftEvent) of object; TGetSubEvent = procedure(s: TSubEvent) of object; TGetRaidEvent = procedure(s: TRaidEvent) of object; - TOnLog = procedure(aModul: string; aMethod: string; aMessage: string; aLevel: integer) of object; + TOnLog = procedure(aModul: string; aMethod: string; aMessage: string; + aLevel: integer) of object; TOnStatus = procedure(Sender: TObject; const ConnectionEvent: String; - StatusCode: Integer; const Description: String) of Object; + StatusCode: integer; const Description: String) of Object; type TTTW_ES = class(TObject) @@ -26,7 +27,7 @@ type wss: TipwWSClient; private - + BroadcasterID: string; FAccessToken: string; FClientID: string; @@ -43,22 +44,23 @@ type FOnStatus: TOnStatus; SW: TWelcomMessage; procedure HandleTimer(Sender: TObject); - procedure ipwWSClient1DataIn(Sender: TObject; DataFormat: Integer; + procedure ipwWSClient1DataIn(Sender: TObject; DataFormat: integer; const Text: string; const TextB: TBytes; EOM, EOL: Boolean); procedure ipwWSPing(Sender: TObject; const Payload: String; const PayloadB: TBytes; Response: Boolean); procedure ipwWSClient1ConnectionStatus(Sender: TObject; - const ConnectionEvent: String; StatusCode: Integer; + const ConnectionEvent: String; StatusCode: integer; const Description: String); - procedure ipwWSClientError(Sender: TObject; ErrorCode: Integer; + procedure ipwWSClientError(Sender: TObject; ErrorCode: integer; const Description: string); - procedure ipwWSClientDisconnected(Sender: TObject; StatusCode: Integer; + procedure ipwWSClientDisconnected(Sender: TObject; StatusCode: integer; const Description: String); procedure ipwWSClientHeader(Sender: TObject; const Field: String; const Value: String); - procedure ipwWSClientLog(Sender: TObject; LogLevel: Integer; + procedure ipwWSClientLog(Sender: TObject; LogLevel: integer; const aMessage, aLog: string); - function subscribeTo(const EventType, Version: string; const Condition: string): Boolean; + function subscribeTo(const EventType, Version: string; + const Condition: string): Boolean; procedure subscribe(); // function ParseRewardRedeemed(const AJsonString: string): TRewardRedeemed; procedure EventMSG(const AText: string); @@ -104,18 +106,14 @@ begin raise Exception.CreateFmt('JSON object "%s" not found', [Name]); end; -function SafeGetStr(Parent: TJSONObject; const Name: string): string; -var - V: TJSONValue; +function GetStrDef(Obj: TJSONObject; const Name: string; + Default: string = ''): string; begin - V := Parent.GetValue(Name); - if Assigned(V) then - Result := V.Value - else - Result := ''; + if not Obj.TryGetValue(Name, Result) then + Result := Default; end; -function SafeGetInt(Parent: TJSONObject; const Name: string): Integer; +function SafeGetInt(Parent: TJSONObject; const Name: string): integer; var V: TJSONValue; begin @@ -143,16 +141,15 @@ begin FOnLog('uTTWEvenSub', aMethod, aMessage, aLevel); end; - - procedure TTTW_ES.Connect; begin - if wss.Connected then + if wss.Connected then wss.Disconnect; try - wss.ConnectTo('wss://eventsub.wss.twitch.tv/ws?keepalive_timeout_seconds=60'); + wss.ConnectTo + ('wss://eventsub.wss.twitch.tv/ws?keepalive_timeout_seconds=60'); toLog(0, 'Connect', 'Подключение к WebSocket выполнено'); FTimer.Enabled := True; except @@ -178,7 +175,7 @@ begin wss.OnDisconnected := ipwWSClientDisconnected; wss.OnHeader := ipwWSClientHeader; - FTimer := TTimer.Create(nil); + FTimer := ttimer.Create(nil); FTimer.Interval := 9000; FTimer.OnTimer := HandleTimer; FTimer.Enabled := False; @@ -188,7 +185,7 @@ end; destructor TTTW_ES.Destroy; begin - toLog(0, 'Destroy', 'Завершение работы EventSub'); + toLog(0, 'Destroy', 'Завершение работы EventSub'); try if Assigned(FTimer) then FreeAndNil(FTimer); @@ -210,6 +207,7 @@ begin try if wss.Connected then wss.Disconnect; + FTimer.Enabled := False; except on E: Exception do toLog(2, 'Disconnect', E.ClassName + ': ' + E.Message); @@ -220,50 +218,55 @@ procedure TTTW_ES.EventMSG(const AText: string); var md: TMetadata; begin - if Assigned(FOnRAW) then - FOnRAW(AText); + TThread.Queue(nil, + procedure + begin - md := ParseMetadata(AText); - toLog(0, 'EventMSG', 'Тип сообщения: ' + md.message_type + ', Тип подписки: ' + md.subscription_type); + if Assigned(FOnRAW) then + FOnRAW(AText); - if md.message_type = 'session_welcome' then - begin - toLog(0, 'EventMSG', 'Получен session_welcome'); - SW := ParseWelcomMessage(AText); - if Assigned(FOnMessage) then - FOnMessage('Welcome message'); - subscribe; - end - else if md.message_type = 'notification' then - begin - if md.subscription_type = 'channel.channel_points_custom_reward_redemption.add' then - if Assigned(FOnGetCustomReward) then - FOnGetCustomReward(ParseCustomRewardEvent(AText)); + md := ParseMetadata(AText); + toLog(0, 'EventMSG', 'Тип сообщения: ' + md.message_type + + ', Тип подписки: ' + md.subscription_type); - if md.subscription_type = 'channel.follow' then - if Assigned(FOnFollow) then - FOnFollow(ParseFollowEvent(AText)); + if md.message_type = 'session_welcome' then + begin + toLog(0, 'EventMSG', 'Получен session_welcome'); + SW := ParseWelcomMessage(AText); + if Assigned(FOnMessage) then + FOnMessage('Welcome message'); + subscribe; + end + else if md.message_type = 'notification' then + begin + if Assigned(FOnGetCustomReward) and + (md.subscription_type = 'channel.channel_points_custom_reward_redemption.add') + then + FOnGetCustomReward(ParseCustomRewardEvent(AText)); - if md.subscription_type = 'channel.subscribe' then - if Assigned(FOnSub) then - FOnSub(ParseSubEvent(AText)); + if Assigned(FOnFollow) and (md.subscription_type = 'channel.follow') + then + FOnFollow(ParseFollowEvent(AText)); - if md.subscription_type = 'channel.subscription.gift' then - if Assigned(FOnGift) then - FOnGift(ParseGiftEvent(AText)); + if Assigned(FOnSub) and (md.subscription_type = 'channel.subscribe') + then + FOnSub(ParseSubEvent(AText)); - if md.subscription_type = 'channel.raid' then - if Assigned(FOnRaid) then - FOnRaid(ParseRaidEvent(AText)); - end - else if md.message_type = 'session_keepalive' then - toLog(3, 'EventMSG', 'Получен keepalive'); + if Assigned(FOnGift) and + (md.subscription_type = 'channel.subscription.gift') then + FOnGift(ParseGiftEvent(AText)); + if Assigned(FOnRaid) and (md.subscription_type = 'channel.raid') then + FOnRaid(ParseRaidEvent(AText)); + end + else if md.message_type = 'session_keepalive' then + toLog(3, 'EventMSG', 'Получен keepalive'); + end); end; procedure TTTW_ES.HandleTimer(Sender: TObject); begin -if wss.Connected then + if wss.Connected then begin toLog(3, 'HandleTimer', 'Отправка ping'); wss.Ping; @@ -271,46 +274,46 @@ if wss.Connected then end; procedure TTTW_ES.ipwWSClient1ConnectionStatus(Sender: TObject; - const ConnectionEvent: String; StatusCode: Integer; - const Description: String); +const ConnectionEvent: String; StatusCode: integer; const Description: String); begin - toLog(0, 'ConnectionStatus', - Format('%s | %d | %s', [ConnectionEvent, StatusCode, Description])); + toLog(0, 'ConnectionStatus', Format('%s | %d | %s', [ConnectionEvent, + StatusCode, Description])); if Assigned(FOnStatus) then FOnStatus(Sender, ConnectionEvent, StatusCode, Description); end; -procedure TTTW_ES.ipwWSClient1DataIn(Sender: TObject; DataFormat: Integer; - const Text: string; const TextB: TBytes; EOM, EOL: Boolean); +procedure TTTW_ES.ipwWSClient1DataIn(Sender: TObject; DataFormat: integer; +const Text: string; const TextB: TBytes; EOM, EOL: Boolean); begin -toLog(3, 'ipwWSClient1DataIn', Text); + toLog(3, 'ipwWSClient1DataIn', Text); EventMSG(Text); end; -procedure TTTW_ES.ipwWSClientDisconnected(Sender: TObject; StatusCode: Integer; - const Description: String); +procedure TTTW_ES.ipwWSClientDisconnected(Sender: TObject; StatusCode: integer; +const Description: String); begin - toLog(1, 'ipwWSClientDisconnected', Description); + toLog(1, 'ipwWSClientDisconnected', Description); end; -procedure TTTW_ES.ipwWSClientError(Sender: TObject; ErrorCode: Integer; - const Description: string); +procedure TTTW_ES.ipwWSClientError(Sender: TObject; ErrorCode: integer; +const Description: string); begin - toLog(2, 'ipwWSClientError', Format('Код: %d | %s', [ErrorCode, Description])); + toLog(2, 'ipwWSClientError', Format('Код: %d | %s', + [ErrorCode, Description])); if Assigned(FOnError) then FOnError(Description); end; procedure TTTW_ES.ipwWSClientHeader(Sender: TObject; - const Field, Value: String); +const Field, Value: String); begin // toLog(3, 'ipwWSClientHeader', // 'Field: ' + Field + ' | Value: ' + Value); end; -procedure TTTW_ES.ipwWSClientLog(Sender: TObject; LogLevel: Integer; - const aMessage, aLog: string); +procedure TTTW_ES.ipwWSClientLog(Sender: TObject; LogLevel: integer; +const aMessage, aLog: string); begin // toLog(3, 'ipwWSClientLog', 'Level: ' + IntToStr(LogLevel) // + ' | ' + aMessage + ' | ' + aLog); @@ -320,9 +323,9 @@ begin end; procedure TTTW_ES.ipwWSPing(Sender: TObject; const Payload: String; - const PayloadB: TBytes; Response: Boolean); +const PayloadB: TBytes; Response: Boolean); begin - toLog(3, 'ipwWSPing', 'PING ' + Payload); + toLog(3, 'ipwWSPing', 'PING ' + Payload); end; function TTTW_ES.ParseMetadata(const JSONString: string): TMetadata; @@ -334,10 +337,10 @@ begin raise Exception.Create('Invalid JSON'); try Metadata := SafeGetObj(Root, 'metadata'); - Result.message_id := SafeGetStr(Metadata, 'message_id'); - Result.message_type := SafeGetStr(Metadata, 'message_type'); - Result.message_timestamp := SafeGetStr(Metadata, 'message_timestamp'); - Result.subscription_type := SafeGetStr(Metadata, 'subscription_type'); + Result.message_id := GetStrDef(Metadata, 'message_id'); + Result.message_type := GetStrDef(Metadata, 'message_type'); + Result.message_timestamp := GetStrDef(Metadata, 'message_timestamp'); + Result.subscription_type := GetStrDef(Metadata, 'subscription_type'); finally Root.Free; end; @@ -353,11 +356,12 @@ begin try Payload := SafeGetObj(Root, 'payload'); Session := SafeGetObj(Payload, 'session'); - Result.Payload.session.id := SafeGetStr(Session, 'id'); - Result.Payload.session.status := SafeGetStr(Session, 'status'); - Result.Payload.session.connected_at := SafeGetStr(Session, 'connected_at'); - Result.Payload.session.keepalive_timeout_seconds := SafeGetInt(Session, 'keepalive_timeout_seconds'); - Result.Payload.session.reconnect_url := SafeGetStr(Session, 'reconnect_url'); + Result.Payload.Session.id := GetStrDef(Session, 'id'); + Result.Payload.Session.status := GetStrDef(Session, 'status'); + Result.Payload.Session.connected_at := GetStrDef(Session, 'connected_at'); + Result.Payload.Session.keepalive_timeout_seconds := + SafeGetInt(Session, 'keepalive_timeout_seconds'); + Result.Payload.Session.reconnect_url := GetStrDef(Session, 'reconnect_url'); finally Root.Free; end; @@ -366,7 +370,8 @@ end; function TTTW_ES.ParseCustomRewardEvent(const JSONString: string) : TCustomRewardEvent; var - Root, Payload, Subscription, mCondition, mTransport, Event, mReward: TJSONObject; + Root, Payload, Subscription, mCondition, mTransport, Event, + mReward: TJSONObject; begin toLog(3, 'ParseCustomRewardEvent', 'Начало парсинга награды'); Root := TJSONObject.ParseJSONValue(JSONString) as TJSONObject; @@ -377,35 +382,36 @@ begin Subscription := SafeGetObj(Payload, 'subscription'); with Result.Subscription do begin - id := SafeGetStr(Subscription, 'id'); - subscription_type := SafeGetStr(Subscription, 'type'); - version := SafeGetStr(Subscription, 'version'); - status := SafeGetStr(Subscription, 'status'); + id := GetStrDef(Subscription, 'id'); + subscription_type := GetStrDef(Subscription, 'type'); + Version := GetStrDef(Subscription, 'version'); + status := GetStrDef(Subscription, 'status'); cost := SafeGetInt(Subscription, 'cost'); - created_at := SafeGetStr(Subscription, 'created_at'); + created_at := GetStrDef(Subscription, 'created_at'); mCondition := SafeGetObj(Subscription, 'condition'); - condition.broadcaster_user_id := SafeGetStr(mCondition, 'broadcaster_user_id'); - condition.reward_id := SafeGetStr(mCondition, 'reward_id'); + Condition.broadcaster_user_id := + GetStrDef(mCondition, 'broadcaster_user_id'); + Condition.reward_id := GetStrDef(mCondition, 'reward_id'); mTransport := SafeGetObj(Subscription, 'transport'); - transport.method := SafeGetStr(mTransport, 'method'); + transport.method := GetStrDef(mTransport, 'method'); end; Event := SafeGetObj(Payload, 'event'); with Result.Event do begin - id := SafeGetStr(Event, 'id'); - broadcaster_user_id := SafeGetStr(Event, 'broadcaster_user_id'); - broadcaster_user_login := SafeGetStr(Event, 'broadcaster_user_login'); - broadcaster_user_name := SafeGetStr(Event, 'broadcaster_user_name'); - user_id := SafeGetStr(Event, 'user_id'); - user_login := SafeGetStr(Event, 'user_login'); - user_name := SafeGetStr(Event, 'user_name'); - user_input := SafeGetStr(Event, 'user_input'); + id := GetStrDef(Event, 'id'); + broadcaster_user_id := GetStrDef(Event, 'broadcaster_user_id'); + broadcaster_user_login := GetStrDef(Event, 'broadcaster_user_login'); + broadcaster_user_name := GetStrDef(Event, 'broadcaster_user_name'); + user_id := GetStrDef(Event, 'user_id'); + user_login := GetStrDef(Event, 'user_login'); + user_name := GetStrDef(Event, 'user_name'); + user_input := GetStrDef(Event, 'user_input'); mReward := SafeGetObj(Event, 'reward'); - revard.id := SafeGetStr(mReward, 'id'); - revard.title := SafeGetStr(mReward, 'title'); + revard.id := GetStrDef(mReward, 'id'); + revard.title := GetStrDef(mReward, 'title'); revard.cost := SafeGetInt(mReward, 'cost'); - revard.prompt := SafeGetStr(mReward, 'prompt'); + revard.prompt := GetStrDef(mReward, 'prompt'); end; finally Root.Free; @@ -425,28 +431,29 @@ begin Subscription := SafeGetObj(Payload, 'subscription'); with Result.Subscription do begin - id := SafeGetStr(Subscription, 'id'); - subscription_type := SafeGetStr(Subscription, 'type'); - version := SafeGetStr(Subscription, 'version'); - status := SafeGetStr(Subscription, 'status'); + id := GetStrDef(Subscription, 'id'); + subscription_type := GetStrDef(Subscription, 'type'); + Version := GetStrDef(Subscription, 'version'); + status := GetStrDef(Subscription, 'status'); cost := SafeGetInt(Subscription, 'cost'); - created_at := SafeGetStr(Subscription, 'created_at'); + created_at := GetStrDef(Subscription, 'created_at'); mCondition := SafeGetObj(Subscription, 'condition'); - condition.broadcaster_user_id := SafeGetStr(mCondition, 'broadcaster_user_id'); + Condition.broadcaster_user_id := + GetStrDef(mCondition, 'broadcaster_user_id'); mTransport := SafeGetObj(Subscription, 'transport'); - transport.method := SafeGetStr(mTransport, 'method'); + transport.method := GetStrDef(mTransport, 'method'); end; Event := SafeGetObj(Payload, 'event'); with Result.Event do begin - broadcaster_user_id := SafeGetStr(Event, 'broadcaster_user_id'); - broadcaster_user_login := SafeGetStr(Event, 'broadcaster_user_login'); - broadcaster_user_name := SafeGetStr(Event, 'broadcaster_user_name'); - user_id := SafeGetStr(Event, 'user_id'); - user_login := SafeGetStr(Event, 'user_login'); - user_name := SafeGetStr(Event, 'user_name'); - followed_at := SafeGetStr(Event, 'followed_at'); + broadcaster_user_id := GetStrDef(Event, 'broadcaster_user_id'); + broadcaster_user_login := GetStrDef(Event, 'broadcaster_user_login'); + broadcaster_user_name := GetStrDef(Event, 'broadcaster_user_name'); + user_id := GetStrDef(Event, 'user_id'); + user_login := GetStrDef(Event, 'user_login'); + user_name := GetStrDef(Event, 'user_name'); + followed_at := GetStrDef(Event, 'followed_at'); end; finally Root.Free; @@ -466,29 +473,30 @@ begin Subscription := SafeGetObj(Payload, 'subscription'); with Result.Subscription do begin - id := SafeGetStr(Subscription, 'id'); - subscription_type := SafeGetStr(Subscription, 'type'); - version := SafeGetStr(Subscription, 'version'); - status := SafeGetStr(Subscription, 'status'); + id := GetStrDef(Subscription, 'id'); + subscription_type := GetStrDef(Subscription, 'type'); + Version := GetStrDef(Subscription, 'version'); + status := GetStrDef(Subscription, 'status'); cost := SafeGetInt(Subscription, 'cost'); - created_at := SafeGetStr(Subscription, 'created_at'); + created_at := GetStrDef(Subscription, 'created_at'); mCondition := SafeGetObj(Subscription, 'condition'); - condition.broadcaster_user_id := SafeGetStr(mCondition, 'broadcaster_user_id'); + Condition.broadcaster_user_id := + GetStrDef(mCondition, 'broadcaster_user_id'); mTransport := SafeGetObj(Subscription, 'transport'); - transport.method := SafeGetStr(mTransport, 'method'); + transport.method := GetStrDef(mTransport, 'method'); end; Event := SafeGetObj(Payload, 'event'); with Result.Event do begin - broadcaster_user_id := SafeGetStr(Event, 'broadcaster_user_id'); - broadcaster_user_login := SafeGetStr(Event, 'broadcaster_user_login'); - broadcaster_user_name := SafeGetStr(Event, 'broadcaster_user_name'); - user_id := SafeGetStr(Event, 'user_id'); - user_login := SafeGetStr(Event, 'user_login'); - user_name := SafeGetStr(Event, 'user_name'); + broadcaster_user_id := GetStrDef(Event, 'broadcaster_user_id'); + broadcaster_user_login := GetStrDef(Event, 'broadcaster_user_login'); + broadcaster_user_name := GetStrDef(Event, 'broadcaster_user_name'); + user_id := GetStrDef(Event, 'user_id'); + user_login := GetStrDef(Event, 'user_login'); + user_name := GetStrDef(Event, 'user_name'); total := SafeGetInt(Event, 'total'); - tier := SafeGetStr(Event, 'tier'); + tier := GetStrDef(Event, 'tier'); cumulative_total := SafeGetInt(Event, 'cumulative_total'); is_anonymous := SafeGetBool(Event, 'anonymous'); end; @@ -497,7 +505,6 @@ begin end; end; - function TTTW_ES.ParseRaidEvent(const JSONString: string): TRaidEvent; var Root, Payload, Subscription, mCondition, mTransport, Event: TJSONObject; @@ -511,27 +518,31 @@ begin Subscription := SafeGetObj(Payload, 'subscription'); with Result.Subscription do begin - id := SafeGetStr(Subscription, 'id'); - subscription_type := SafeGetStr(Subscription, 'type'); - version := SafeGetStr(Subscription, 'version'); - status := SafeGetStr(Subscription, 'status'); + id := GetStrDef(Subscription, 'id'); + subscription_type := GetStrDef(Subscription, 'type'); + Version := GetStrDef(Subscription, 'version'); + status := GetStrDef(Subscription, 'status'); cost := SafeGetInt(Subscription, 'cost'); - created_at := SafeGetStr(Subscription, 'created_at'); + created_at := GetStrDef(Subscription, 'created_at'); mCondition := SafeGetObj(Subscription, 'condition'); - condition.broadcaster_user_id := SafeGetStr(mCondition, 'to_broadcaster_user_id'); + Condition.broadcaster_user_id := + GetStrDef(mCondition, 'to_broadcaster_user_id'); mTransport := SafeGetObj(Subscription, 'transport'); - transport.method := SafeGetStr(mTransport, 'method'); + transport.method := GetStrDef(mTransport, 'method'); end; Event := SafeGetObj(Payload, 'event'); with Result.Event do begin - from_broadcaster_user_id := SafeGetStr(Event, 'from_broadcaster_user_id'); - from_broadcaster_user_login := SafeGetStr(Event, 'from_broadcaster_user_login'); - from_broadcaster_user_name := SafeGetStr(Event, 'from_broadcaster_user_name'); - to_broadcaster_user_id := SafeGetStr(Event, 'to_broadcaster_user_id'); - to_broadcaster_user_login := SafeGetStr(Event, 'to_broadcaster_user_login'); - to_broadcaster_user_name := SafeGetStr(Event, 'to_broadcaster_user_name'); + from_broadcaster_user_id := GetStrDef(Event, 'from_broadcaster_user_id'); + from_broadcaster_user_login := + GetStrDef(Event, 'from_broadcaster_user_login'); + from_broadcaster_user_name := + GetStrDef(Event, 'from_broadcaster_user_name'); + to_broadcaster_user_id := GetStrDef(Event, 'to_broadcaster_user_id'); + to_broadcaster_user_login := + GetStrDef(Event, 'to_broadcaster_user_login'); + to_broadcaster_user_name := GetStrDef(Event, 'to_broadcaster_user_name'); viewers := SafeGetInt(Event, 'viewers'); end; finally @@ -552,28 +563,29 @@ begin Subscription := SafeGetObj(Payload, 'subscription'); with Result.Subscription do begin - id := SafeGetStr(Subscription, 'id'); - subscription_type := SafeGetStr(Subscription, 'type'); - version := SafeGetStr(Subscription, 'version'); - status := SafeGetStr(Subscription, 'status'); + id := GetStrDef(Subscription, 'id'); + subscription_type := GetStrDef(Subscription, 'type'); + Version := GetStrDef(Subscription, 'version'); + status := GetStrDef(Subscription, 'status'); cost := SafeGetInt(Subscription, 'cost'); - created_at := SafeGetStr(Subscription, 'created_at'); + created_at := GetStrDef(Subscription, 'created_at'); mCondition := SafeGetObj(Subscription, 'condition'); - condition.broadcaster_user_id := SafeGetStr(mCondition, 'broadcaster_user_id'); + Condition.broadcaster_user_id := + GetStrDef(mCondition, 'broadcaster_user_id'); mTransport := SafeGetObj(Subscription, 'transport'); - transport.method := SafeGetStr(mTransport, 'method'); + transport.method := GetStrDef(mTransport, 'method'); end; Event := SafeGetObj(Payload, 'event'); with Result.Event do begin - broadcaster_user_id := SafeGetStr(Event, 'broadcaster_user_id'); - broadcaster_user_login := SafeGetStr(Event, 'broadcaster_user_login'); - broadcaster_user_name := SafeGetStr(Event, 'broadcaster_user_name'); - user_id := SafeGetStr(Event, 'user_id'); - user_login := SafeGetStr(Event, 'user_login'); - user_name := SafeGetStr(Event, 'user_name'); - tier := SafeGetStr(Event, 'tier'); + broadcaster_user_id := GetStrDef(Event, 'broadcaster_user_id'); + broadcaster_user_login := GetStrDef(Event, 'broadcaster_user_login'); + broadcaster_user_name := GetStrDef(Event, 'broadcaster_user_name'); + user_id := GetStrDef(Event, 'user_id'); + user_login := GetStrDef(Event, 'user_login'); + user_name := GetStrDef(Event, 'user_name'); + tier := GetStrDef(Event, 'tier'); is_gift := SafeGetBool(Event, 'is_gift'); end; finally @@ -581,45 +593,45 @@ begin end; end; -function TTTW_ES.subscribeTo(const EventType, Version: string; const Condition: string): Boolean; +function TTTW_ES.subscribeTo(const EventType, Version: string; +const Condition: string): Boolean; var - Json: TStringStream; + JSON: TStringStream; Resp: string; HTTP: TNetHTTPClient; begin Result := False; toLog(0, 'subscribeTo', 'Подписка на ' + EventType); - - HTTP := TNetHTTPClient.Create(nil); try - HTTP.ContentType := 'application/json'; - HTTP.CustomHeaders['Authorization'] := 'Bearer ' + FAccessToken; - HTTP.CustomHeaders['Client-Id'] := FClientID; - - Json := TStringStream.Create( - TJSONObject.Create - .AddPair('type', EventType) - .AddPair('version', Version) - .AddPair('condition', TJSONObject.ParseJSONValue(Condition) as TJSONObject) - .AddPair('transport', - TJSONObject.Create - .AddPair('method', 'websocket') - .AddPair('session_id', SW.Payload.session.id) - ).ToJSON, TEncoding.UTF8 - ); + HTTP := TNetHTTPClient.Create(nil); try - Resp := HTTP.Post('https://api.twitch.tv/helix/eventsub/subscriptions', Json).ContentAsString(); - toLog(3, 'subscribeTo', 'Ответ Twitch: ' + Resp); + HTTP.ContentType := 'application/json'; + HTTP.CustomHeaders['Authorization'] := 'Bearer ' + FAccessToken; + HTTP.CustomHeaders['Client-Id'] := FClientID; + + JSON := TStringStream.Create(TJSONObject.Create.AddPair('type', EventType) + .AddPair('version', Version).AddPair('condition', + TJSONObject.ParseJSONValue(Condition) as TJSONObject) + .AddPair('transport', TJSONObject.Create.AddPair('method', 'websocket') + .AddPair('session_id', SW.Payload.Session.id)).ToJSON, TEncoding.UTF8); + try + Resp := HTTP.Post('https://api.twitch.tv/helix/eventsub/subscriptions', + JSON).ContentAsString(); + toLog(3, 'subscribeTo', 'Ответ Twitch: ' + Resp); + + if Pos('"status":"enabled"', Resp) > 0 then + begin + toLog(0, 'subscribeTo', 'Подписка успешна'); + Result := True; + end + else + toLog(1, 'subscribeTo', 'Подписка не подтверждена: ' + Resp); + finally + JSON.Free; + end; - if Pos('"status":"enabled"', Resp) > 0 then - begin - toLog(0, 'subscribeTo', 'Подписка успешна'); - Result := True; - end - else - toLog(1, 'subscribeTo', 'Подписка не подтверждена: ' + Resp); finally - Json.Free; + HTTP.Free; end; except on E: Exception do @@ -636,35 +648,35 @@ begin // channel.raid (1) if subscribeTo('channel.channel_points_custom_reward_redemption.add', '1', '{"broadcaster_user_id":"' + BroadcasterID + '"}') then - toLog(0, 'subscribe', + toLog(0, 'subscribe', 'channel.channel_points_custom_reward_redemption.add OK') else - toLog(2, 'subscribe', + toLog(2, 'subscribe', 'channel.channel_points_custom_reward_redemption.add'); if subscribeTo('channel.raid', '1', '{"to_broadcaster_user_id":"' + BroadcasterID + '"}') then - toLog(0, 'subscribe', 'channel.raid OK') + toLog(0, 'subscribe', 'channel.raid OK') else - toLog(2, 'subscribe', 'channel.raid'); + toLog(2, 'subscribe', 'channel.raid'); if subscribeTo('channel.follow', '2', '{"broadcaster_user_id":"' + BroadcasterID + '","moderator_user_id":"' + BroadcasterID + '"}') then - toLog(0, 'subscribe', 'channel.follow OK') + toLog(0, 'subscribe', 'channel.follow OK') else - toLog(2, 'subscribe', 'channel.follow'); + toLog(2, 'subscribe', 'channel.follow'); if subscribeTo('channel.subscribe', '1', '{"broadcaster_user_id":"' + BroadcasterID + '"}') then - toLog(0, 'subscribe', 'channel.subscribe OK') + toLog(0, 'subscribe', 'channel.subscribe OK') else - toLog(2, 'subscribe', 'channel.subscribe'); + toLog(2, 'subscribe', 'channel.subscribe'); if subscribeTo('channel.subscription.gift', '1', '{"broadcaster_user_id":"' + BroadcasterID + '"}') then - toLog(0, 'subscribe', 'channel.subscription.gift OK') + toLog(0, 'subscribe', 'channel.subscription.gift OK') else - toLog(2, 'subscribe', 'channel.subscription.gift'); + toLog(2, 'subscribe', 'channel.subscription.gift'); end; end. diff --git a/forms/uGeneral.pas b/forms/uGeneral.pas index 04c0ad7..5053210 100644 --- a/forms/uGeneral.pas +++ b/forms/uGeneral.pas @@ -272,7 +272,7 @@ begin frSettings1.edtBotClientID.text, rid); // Назначение обработчиков событий - // ttw_ES.OnMessage := fRewards.ESOnMessage; + ttw_ES.OnLog := toLog; ttw_ES.OnError := ESError; ttw_ES.OnGetCustomReward := frEvents1.ESOnGetCustomReward; ttw_ES.OnStatus := ESStatus; @@ -513,23 +513,25 @@ end; procedure TTTW_Bot.FormDestroy(Sender: TObject); begin - frOBS1.ChatBadges.Free; - frOBS1.ChatEmotes.Free; - frOBS1.ChatWebServers.Free; - frOBS1.EventWebServers.Free; - frOBS1.KandinskyWebServers.Free; - frRevards1.CustomRewards.Free; + FreeAndNil(frOBS1.ChatBadges); + FreeAndNil(frOBS1.ChatEmotes); + FreeAndNil(frOBS1.ChatWebServers); +FreeAndNil(frOBS1.EventWebServers); +FreeAndNil(frOBS1.KandinskyWebServers); +FreeAndNil(frRevards1.CustomRewards); + + frOBS1.BTTV.Free; + frOBS1.m7tv.Free; + userlist.Free; kePoints.Free; + DisconnectProcedure; - if Assigned(ttw_IRS) then - ttw_IRS.Free; - if Assigned(ttw_ES) then - ttw_ES.Free; + FreeAndNil(ttw_IRS); + FreeAndNil(ttw_ES); + FreeAndNil(ttw_API); if Assigned(Kandinsky) then Kandinsky.Free; - if Assigned(ttw_API) then - ttw_API.Free; - frSettings1.Destroy; + //frSettings1.Destroy; FreeAndNil(db); FreeAndNil(frAutoActions1.FTimerList); FreeAndNil(frLog1.FLogList); diff --git a/utils/uPlayerThread.pas b/utils/uPlayerThread.pas index 59fd555..4f255fd 100644 --- a/utils/uPlayerThread.pas +++ b/utils/uPlayerThread.pas @@ -60,7 +60,7 @@ begin finally FQueueCS.Leave; end; - FQueueCS.Free; + FreeAndNil(FQueueCS); inherited; end; diff --git a/utils/uWebServerEvents.pas b/utils/uWebServerEvents.pas index 604dc90..72c215e 100644 --- a/utils/uWebServerEvents.pas +++ b/utils/uWebServerEvents.pas @@ -52,7 +52,7 @@ end; destructor TTTW_Events.Destroy; begin - FCriticalSection.Free; + FreeAndNil(FCriticalSection); FMessages.Free; fFontsList.Free; IdHTTPServer1.Free; @@ -180,6 +180,8 @@ var begin JSONArray := TJSONArray.Create; try + CleanupOldMessages; + FCriticalSection.Enter; try for I := 0 to FMessages.Count - 1 do diff --git a/utils/uWebServerKandinsky.pas b/utils/uWebServerKandinsky.pas index 5807f1f..ca696e1 100644 --- a/utils/uWebServerKandinsky.pas +++ b/utils/uWebServerKandinsky.pas @@ -67,7 +67,7 @@ end; destructor TKandinsky_Web.Destroy; begin IdHTTPServer1.Active := False; - FCriticalSection.Free; + FreeAndNil(FCriticalSection); CleanupOldMessages; end;