unit uTTWAPI; interface uses System.Classes, System.SysUtils, IdHTTP, IdSSLOpenSSL, System.JSON, FMX.Forms, IdMultipartFormData, DateUtils, uDataBase, System.Generics.Collections, uRecords; type TTTW_API = class(TObject) private Token_api: string; Token_api_streamer: string; ClientID: string; channel_name_api: string; BotName_api: string; FChatBadges:tlist; function GetFollowedAtFromJson(jsonString: string): string; function getTTW(method: string; ClientID: string; isStreamer: boolean = false): string; function DelTTW(method: string; ClientID: string; isStreamer: boolean = false): string; function postTTW(method: string; ClientID: string; params: TIdMultipartFormDataStream; isStreamer: boolean = false) : string; overload; function postTTW(method: string; ClientID: string; params: TStringStream; isStreamer: boolean = false): string; overload; function patchTTW(method: string; ClientID: string; params: TStringStream; isStreamer: boolean = false): string; overload; public constructor Create(Sender: TObject); destructor Destroy; override; procedure Init(myClient, myToken, streamerToken, Channel, myBotName: string); procedure getTTWStat(Channel: string; var avg_viewers: integer; var max_viewers: integer; var hours_watched: integer; var followers: integer; var followers_total: integer); procedure shoutouts(id: string); procedure SendNotify(text: string); procedure banUser(id: string); procedure banUserTime(id: string; aTime: integer); procedure unBanUser(id: string); procedure warnUser(id: string); procedure raid(id: string); procedure unRaid(); procedure setModerator(id: string); procedure delModerator(id: string); procedure setVIP(id: string); procedure delVIP(id: string); procedure getCustomReward(var acr: Tlist); function createCustomReward(title: string; cost: string; promt: string = ''; isUserInput: boolean = false):TCustomRevards; procedure UpdateCustomReward(ahr: TCustomRevards); procedure UpdateRedemptionStatus(ahr: TCustomRewardEvent); procedure deleteCustomReward(id: string); function getRoomAndBot():string; function getUserbyLogin(login: string): TUser; function getFollow(id: string): tdatetime; function GetRoomID: string; procedure getGlobalChatBadges(var gcb: Tlist); procedure getCustomChatBadges(var ccb: Tlist); procedure GetChannelEmotes(var ce: Tlist); procedure GetGlobalEmotes(var ge: Tlist); function ValidateTwitchToken(const TokenName, TokenValue: string; var DayOfLive:integer): Boolean; end; TChatBadges = TList; TEmotesList = TList; var room_id: string = ''; bot_id: string = ''; implementation uses uGeneral; constructor TTTW_API.Create(Sender: TObject); begin // Инициализация end; function TTTW_API.createCustomReward(title: string; cost: string; promt: string = ''; isUserInput: boolean = false):TCustomRevards; var RequestData: TStringStream; s, s1, json: string; i:integer; cr:TCustomRevards; JSONData:TJSONObject; JSONArray:TJSONArray; begin try if room_id = '' then room_id:=GetRoomID ; s := ''; s1 := ''; if isUserInput then s := ' "is_user_input_required":true,'; if promt <> '' then s1 := ' "prompt":"' + promt + '",'; RequestData := TStringStream.Create('{ "title":"' + title + '", ' + s + s1 + ' "cost":' + cost + ' }', CP_UTF8); json := postTTW('channel_points/custom_rewards?broadcaster_id=' + room_id, ClientID, RequestData, true); if json = '' then // fLog.toLog(1,'TTW_API','createCustomReward','Награда не создалась, запрос врнул пустой ответ'); JSONData := TJSONObject.ParseJSONValue(JSON) as TJSONObject; try if Assigned(JSONData) then begin JSONArray := JSONData.GetValue('data'); for i := 0 to JSONArray.Count - 1 do begin cr.id := JSONArray.Items[i].GetValue('id'); cr.title := JSONArray.Items[i].GetValue('title'); cr.promt := JSONArray.Items[i].GetValue('prompt'); cr.cost := JSONArray.Items[i].GetValue('cost'); cr.is_user_input_required := JSONArray.Items[i].GetValue ('is_user_input_required'); end; end; finally JSONData.Free; end; result:=cr; except on E: Exception do // Form1.Log(2, 'TTTW_API.createCustomReward', E.Message); // flog.toLog(2,'TTW_API','createCustomReward',E.Message); end; end; destructor TTTW_API.Destroy; begin // Освобождение ресурсов inherited; end; procedure TTTW_API.Init(myClient, myToken, streamerToken, Channel, myBotName: string); begin ClientID := myClient; Token_api := myToken; Token_api_streamer := streamerToken; channel_name_api := Channel; BotName_api := myBotName; end; procedure TTTW_API.banUser(id: string); var RequestData: TStringStream; begin try if bot_id = '' then exit; if room_id = '' then exit; RequestData := TStringStream.Create('{"data": {"user_id":"' + id + '","reason":"no reason"}}'); try postTTW('moderation/bans?broadcaster_id=' + room_id + '&moderator_id=' + bot_id, ClientID, RequestData); finally RequestData.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.banUser', E.Message); // flog.toLog(2,'TTW_API','banUser',E.Message); end; end; procedure TTTW_API.banUserTime(id: string; aTime: integer); var RequestData: TStringStream; begin try if bot_id = '' then exit; if room_id = '' then exit; RequestData := TStringStream.Create('{"data": {"user_id":"' + id + '","duration":' + inttostr(aTime) + '}}'); try postTTW('moderation/bans?broadcaster_id=' + room_id + '&moderator_id=' + bot_id, ClientID, RequestData); finally RequestData.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.banUserTime', E.Message); // flog.toLog(2,'TTW_API','banUserTime',E.Message); end; end; procedure TTTW_API.deleteCustomReward(id: string); begin try if Token_api_streamer = '' then exit; if room_id = '' then exit; DelTTW('channel_points/custom_rewards?broadcaster_id=' + room_id + '&id=' + id, ClientID, true); except on E: Exception do ///Form1.Log(2, 'TTTW_API.deleteCustomReward', E.Message); // flog.toLog(2,'TTW_API','deleteCustomReward',E.Message); end; end; procedure TTTW_API.delModerator(id: string); begin try if Token_api_streamer = '' then exit; if room_id = '' then exit; DelTTW('moderation/moderators?broadcaster_id=' + room_id + '&user_id=' + id, ClientID, true); except on E: Exception do //Form1.Log(2, 'TTTW_API.delModerator', E.Message); // flog.toLog(2,'TTW_API','delModerator',E.Message); end; end; function TTTW_API.DelTTW(method, ClientID: string; isStreamer: boolean): string; var url: string; response1, Token: string; http: TIdHTTP; ssl: TIdSSLIOHandlerSocketOpenSSL; begin Result := ''; http := TIdHTTP.Create(nil); ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil); try try if isStreamer then Token := Token_api_streamer else Token := Token_api; http.IOHandler := ssl; ssl.SSLOptions.method := sslvSSLv23; http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; http.Request.CustomHeaders.AddValue('Client-ID', ClientID); http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + Token); http.Request.ContentType := 'application/json'; url := 'https://api.twitch.tv/helix/' + method; response1 := http.Delete(url); Result := response1; except on E: Exception do //Form1.Log(2, 'TTTW_API.DelTTW', E.Message+' ['+method+']'); // flog.toLog(2,'TTW_API','DelTTW',E.Message+' ['+method+']'); end; finally http.Free; ssl.Free; end; end; procedure TTTW_API.delVIP(id: string); begin try if Token_api_streamer = '' then exit; if room_id = '' then exit; DelTTW('channels/vips?broadcaster_id=' + room_id + '&user_id=' + id, ClientID, true); except on E: Exception do //Form1.Log(2, 'TTTW_API.delVIP', E.Message); // flog.toLog(2,'TTW_API','delVIP',E.Message); end; end; procedure TTTW_API.getCustomReward(var acr: Tlist); var JSON: string; sl: TCustomRevards; JSONData: TJSONObject; JSONArray: TJSONArray; i: integer; begin try if Token_api_streamer = '' then begin exit; end; if room_id = '' then exit; JSON := getTTW('channel_points/custom_rewards?broadcaster_id=' + room_id + '&only_manageable_rewards=true', ClientID, true); JSONData := TJSONObject.ParseJSONValue(JSON) as TJSONObject; try if Assigned(JSONData) then begin JSONArray := JSONData.GetValue('data'); for i := 0 to JSONArray.Count - 1 do begin sl.id := JSONArray.Items[i].GetValue('id'); sl.title := JSONArray.Items[i].GetValue('title'); sl.promt := JSONArray.Items[i].GetValue('prompt'); sl.cost := JSONArray.Items[i].GetValue('cost'); sl.is_user_input_required := JSONArray.Items[i].GetValue ('is_user_input_required'); acr.add(sl); end; end; finally JSONData.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.getCustomReward', E.Message); // flog.toLog(2,'TTW_API','getCustomReward',E.Message); end; end; function TTTW_API.getFollow(id: string): tdatetime; var s: string; begin s := getTTW('channels/followers?user_id=' + id + '&broadcaster_id=' + room_id, ClientID); Result := strToDate(GetFollowedAtFromJson(s)); end; function TTTW_API.GetFollowedAtFromJson(jsonString: string): string; var JSON: TJSONObject; dataArray: TJSONArray; begin Result := ''; JSON := TJSONObject.ParseJSONValue(jsonString) as TJSONObject; try if Assigned(JSON) then begin dataArray := JSON.GetValue('data') as TJSONArray; if Assigned(dataArray) and (dataArray.Count > 0) then Result := DateToStr (ISO8601ToDate(dataArray.Items[0].GetValue('followed_at'))); end; finally JSON.Free; end; end; function TTTW_API.getTTW(method, ClientID: string; isStreamer: boolean): string; var url: string; response1, Token: string; http: TIdHTTP; ssl: TIdSSLIOHandlerSocketOpenSSL; begin Result := ''; http := TIdHTTP.Create(nil); ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil); try try if isStreamer then Token := Token_api_streamer else Token := Token_api; http.IOHandler := ssl; ssl.SSLOptions.method := sslvSSLv23; http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; http.Request.CustomHeaders.AddValue('Client-ID', ClientID); http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + Token); url := 'https://api.twitch.tv/helix/' + method; response1 := http.Get(url); Result := response1; except on E: Exception do ////Form1.Log(2, 'TTTW_API.getTTW', E.Message+' ['+method+']'); // flog.toLog(2,'TTW_API','getTTW',E.Message+' ['+method+']'); end; finally http.Free; ssl.Free; end; end; procedure TTTW_API.getTTWStat(Channel: string; var avg_viewers, max_viewers, hours_watched, followers, followers_total: integer); var jsonObject: TJSONObject; url: string; response1: string; http: TIdHTTP; ssl: TIdSSLIOHandlerSocketOpenSSL; begin http := TIdHTTP.Create(nil); ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil); try try http.IOHandler := ssl; ssl.SSLOptions.method := sslvSSLv23; http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; url := 'https://twitchtracker.com/api/channels/summary/' + Channel; response1 := http.Get(url); jsonObject := TJSONObject.ParseJSONValue(response1) as TJSONObject; try if Assigned(jsonObject) then begin avg_viewers := jsonObject.GetValue('avg_viewers'); max_viewers := jsonObject.GetValue('max_viewers'); hours_watched := jsonObject.GetValue('hours_watched'); followers := jsonObject.GetValue('followers'); followers_total := jsonObject.GetValue('followers_total'); end; finally if Assigned(jsonObject) then jsonObject.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.getTTWStat', E.Message); // flog.toLog(2,'TTW_API','getTTWStat',E.Message); end; finally http.Free; ssl.Free; end; end; function ParseBadgeVersion(VersionObj: TJSONObject): TBadgeVersion; begin // Добавьте проверки на nil для каждого поля Result.Id := VersionObj.GetValue('id').Value; Result.ImageUrl1x := VersionObj.GetValue('image_url_1x').Value; Result.ImageUrl2x := VersionObj.GetValue('image_url_2x').Value; Result.ImageUrl4x := VersionObj.GetValue('image_url_4x').Value; Result.Title := VersionObj.GetValue('title').Value; Result.Description := VersionObj.GetValue('description').Value; Result.ClickAction := VersionObj.GetValue('click_action').Value; Result.ClickUrl := VersionObj.GetValue('click_url').Value; end; function ParseChatBadge(BadgeObj: TJSONObject): TChatBadge; var VersionsArray: TJSONArray; I: Integer; begin // Добавьте проверки на nil для каждого поля Result.SetId := BadgeObj.GetValue('set_id').Value; VersionsArray := BadgeObj.GetValue('versions') as TJSONArray; SetLength(Result.Versions, VersionsArray.Count); for I := 0 to VersionsArray.Count - 1 do Result.Versions[I] := ParseBadgeVersion(VersionsArray.Items[I] as TJSONObject); end; procedure ParseBadgesFromApi(const JSONResponse: string; Badges: TChatBadges); var RootObj: TJSONObject; DataArray: TJSONArray; I: Integer; Badge: TChatBadge; begin RootObj := TJSONObject.ParseJSONValue(JSONResponse) as TJSONObject; try DataArray := RootObj.GetValue('data') as TJSONArray; for I := 0 to DataArray.Count - 1 do begin Badge := ParseChatBadge(DataArray.Items[I] as TJSONObject); Badges.Add(Badge); end; finally RootObj.Free; end; end; procedure TTTW_API.getGlobalChatBadges(var gcb: Tlist); var jsonString: string; global:TChatBadge; begin JSONString:=getTTW('chat/badges/global',ClientID,false); ParseBadgesFromApi(JSONString,gcb); end; procedure TTTW_API.getCustomChatBadges(var ccb: Tlist); var jsonString: string; begin JSONString:=getTTW('chat/badges?broadcaster_id='+room_id,ClientID,false); ParseBadgesFromApi(JSONString,ccb); end; function TTTW_API.getRoomAndBot():string; var jsonString: string; JSON: TJSONObject; dataArray: TJSONArray; begin try jsonString := getTTW('users?login=' + LowerCase(BotName_api), ClientID); JSON := TJSONObject.ParseJSONValue(jsonString) as TJSONObject; try if Assigned(JSON) then begin dataArray := JSON.GetValue('data') as TJSONArray; if Assigned(dataArray) and (dataArray.Count > 0) then begin bot_id := dataArray.Items[0].GetValue('id'); end; end; finally JSON.Free; end; except on E: Exception do // fLog.toLog(2,'TTW_API','getRoomAndBot.GetBotID',e.Message); end; try jsonString := getTTW('users?login=' + LowerCase(channel_name_api), ClientID); JSON := TJSONObject.ParseJSONValue(jsonString) as TJSONObject; try if Assigned(JSON) then begin dataArray := JSON.GetValue('data') as TJSONArray; if Assigned(dataArray) and (dataArray.Count > 0) then begin room_id := dataArray.Items[0].GetValue('id'); end; end; finally JSON.Free; end; except on E: Exception do // fLog.toLog(2,'TTW_API','getRoomAndBot.GetRoomID',e.Message); end; result:=room_id; end; function TTTW_API.GetRoomID: string; begin Result := room_id; end; function TTTW_API.getUserbyLogin(login: string): TUser; var u: TUser; JSON: TJSONObject; dataArray: TJSONArray; jsonString: string; begin jsonString := getTTW('users?login=' + LowerCase(login), ClientID); JSON := TJSONObject.ParseJSONValue(jsonString) as TJSONObject; try if Assigned(JSON) then begin dataArray := JSON.GetValue('data') as TJSONArray; if Assigned(dataArray) and (dataArray.Count > 0) then begin u.id := dataArray.Items[0].GetValue('id'); u.login := dataArray.Items[0].GetValue('login'); u.DisplayName := dataArray.Items[0].GetValue('display_name'); u.created_at := ISO8601ToDate (dataArray.Items[0].GetValue('created_at')); end; end; finally JSON.Free; end; Result := u; end; function TTTW_API.postTTW(method, ClientID: string; params: TIdMultipartFormDataStream; isStreamer: boolean): string; var url: string; response1, Token: string; http: TIdHTTP; ssl: TIdSSLIOHandlerSocketOpenSSL; begin Result := ''; http := TIdHTTP.Create(nil); ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil); try try if isStreamer then Token := Token_api_streamer else Token := Token_api; http.IOHandler := ssl; ssl.SSLOptions.method := sslvSSLv23; http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; http.Request.CustomHeaders.AddValue('Client-ID', ClientID); http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + Token); http.Request.ContentType := 'application/json'; url := 'https://api.twitch.tv/helix/' + method; response1 := http.Post(url, params); Result := response1; except on E: Exception do //Form1.Log(2, 'TTTW_API.postTTW', E.Message+' ['+method+']'); // flog.toLog(2,'TTW_API','postTTW',E.Message+' ['+method+']'); end; finally http.Free; ssl.Free; end; end; function TTTW_API.patchTTW(method, ClientID: string; params: TStringStream; isStreamer: boolean): string; var url: string; response1, Token: string; http: TIdHTTP; ssl: TIdSSLIOHandlerSocketOpenSSL; begin Result := ''; http := TIdHTTP.Create(nil); ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil); try try if isStreamer then Token := Token_api_streamer else Token := Token_api; http.IOHandler := ssl; ssl.SSLOptions.method := sslvSSLv23; http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; http.Request.CustomHeaders.AddValue('Client-ID', ClientID); http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + Token); http.Request.ContentType := 'application/json'; url := 'https://api.twitch.tv/helix/' + method; response1 := http.Patch(url, params); Result := response1; except on E: Exception do //Form1.Log(2, 'TTTW_API.patchTTW', E.Message+' ['+method+']'); //flog.toLog(2,'TTW_API','patchTTW',E.Message+' ['+method+']'); end; finally http.Free; ssl.Free; end; end; function TTTW_API.postTTW(method, ClientID: string; params: TStringStream; isStreamer: boolean): string; var url: string; response1, Token: string; http: TIdHTTP; ssl: TIdSSLIOHandlerSocketOpenSSL; begin Result := ''; http := TIdHTTP.Create(nil); ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil); try try if isStreamer then Token := Token_api_streamer else Token := Token_api; http.IOHandler := ssl; ssl.SSLOptions.method := sslvSSLv23; http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; http.Request.CustomHeaders.AddValue('Client-ID', ClientID); http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + Token); http.Request.ContentType := 'application/json'; url := 'https://api.twitch.tv/helix/' + method; response1 := http.Post(url, params); Result := response1; except on E: Exception do //Form1.Log(2, 'TTTW_API.postTTW', E.Message+' ['+method+']'); //flog.toLog(2,'TTW_API','postTTW',E.Message+' ['+method+']'); end; finally http.Free; ssl.Free; end; end; procedure TTTW_API.raid(id: string); var p: TIdMultipartFormDataStream; begin try if room_id = '' then exit; p := TIdMultipartFormDataStream.Create; try postTTW('raids?from_broadcaster_id=' + room_id + '&to_broadcaster_id=' + id, ClientID, p, true); finally p.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.raid', E.Message); // flog.toLog(2,'TTW_API','raid',E.Message); end; end; procedure TTTW_API.SendNotify(text: string); var p: TStringStream; begin try if bot_id = '' then begin //flog.toLog(1,'TTW_API','SendNotify','bot_id пуст. Исправляю'); getRoomAndBot; if bot_id = '' then begin // flog.toLog(2,'TTW_API','SendNotify','bot_id все равно пуст'); exit; end; end; if room_id = '' then begin // flog.toLog(2,'TTW_API','SendNotify','room_id пуст'); exit; end; p := TStringStream.Create('{"message":"' + text + '","color":"primary"}', CP_UTF8); try postTTW('chat/announcements?broadcaster_id=' + room_id + '&moderator_id=' + bot_id, ClientID, p); finally p.Free; end; except on E: Exception do // flog.toLog(2,'TTW_API','SendNotify',E.Message); end; end; procedure TTTW_API.setModerator(id: string); var RequestData: TStringStream; begin try if Token_api_streamer = '' then exit; if room_id = '' then exit; RequestData := TStringStream.Create(''); try postTTW('moderation/moderators?broadcaster_id=' + room_id + '&user_id=' + id, ClientID, RequestData, true); finally RequestData.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.setModerator', E.Message); // flog.toLog(2,'TTW_API','setModerator',E.Message); end; end; procedure TTTW_API.setVIP(id: string); var userID: string; RequestData: TStringStream; begin try if Token_api_streamer = '' then exit; if room_id = '' then exit; RequestData := TStringStream.Create(''); try postTTW('channels/vips?broadcaster_id=' + room_id + '&user_id=' + userID, ClientID, RequestData, true); finally RequestData.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.setVIP', E.Message); // flog.toLog(2,'TTW_API','setVIP',E.Message); end; end; procedure TTTW_API.shoutouts(id: string); var p: TIdMultipartFormDataStream; begin try if bot_id = '' then exit; if room_id = '' then exit; p := TIdMultipartFormDataStream.Create; try postTTW('chat/shoutouts?from_broadcaster_id=' + room_id + '&to_broadcaster_id=' + id + '&moderator_id=' + bot_id, ClientID, p); finally p.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.shoutouts', E.Message); // flog.toLog(2,'TTW_API','shoutouts',E.Message); end; end; procedure TTTW_API.unBanUser(id: string); begin try if bot_id = '' then exit; if room_id = '' then exit; DelTTW('moderation/bans?broadcaster_id=' + room_id + '&moderator_id=' + bot_id + '&user_id=' + id, ClientID); except on E: Exception do //Form1.Log(2, 'TTTW_API.unBanUser', E.Message); // flog.toLog(2,'TTW_API','unBanUser',E.Message); end; end; procedure TTTW_API.unRaid; begin try if room_id = '' then exit; DelTTW('raids?broadcaster_id=' + room_id, ClientID); except on E: Exception do //Form1.Log(2, 'TTTW_API.unRaid', E.Message); // flog.toLog(2,'TTW_API','unRaid',E.Message); end; end; procedure TTTW_API.UpdateCustomReward(ahr: TCustomRevards); var RequestData: TStringStream; qid: string; begin try if room_id = '' then exit; qid := ahr.id; RequestData := TStringStream.Create('{"cost": ' + inttostr(ahr.cost) + '}', CP_UTF8); try patchTTW('channel_points/custom_rewards?broadcaster_id=' + room_id + '&id=' + qid, ClientID, RequestData, true); finally RequestData.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.UpdateCustomReward', E.Message); // flog.toLog(2,'TTW_API','UpdateCustomReward',E.Message); end; end; procedure TTTW_API.UpdateRedemptionStatus(ahr: TCustomRewardEvent); var qbid, qrid, qid: string; RequestData: TStringStream; begin try if bot_id = '' then exit; if room_id = '' then exit; qbid := ahr.event.broadcaster_user_id; qrid := ahr.event.revard.id; qid := ahr.event.id; //Form1.Log(1, 'TTTW_API.UpdateRedemptionStatus', 'ChannelId: ' + qbid + // '; Reward.id: ' + qrid + '; Redemption.id: ' + qid); // flog.toLog(1,'TTW_API','UpdateRedemptionStatus','ChannelId: ' + qbid + // '; Reward.id: ' + qrid + '; Redemption.id: ' + qid); RequestData := TStringStream.Create('{"status":"CANCELED"}', CP_UTF8); try patchTTW('channel_points/custom_rewards/redemptions?broadcaster_id=' + qbid + '&reward_id=' + qrid + '&id=' + qid, ClientID, RequestData, true); finally RequestData.Free; end; except on E: Exception do // Form1.Log(2, 'TTTW_API.UpdateRedemptionStatus', E.Message); // flog.toLog(2,'TTW_API','UpdateRedemptionStatus',E.Message); end; end; function TTTW_API.ValidateTwitchToken(const TokenName, TokenValue: string; var DayOfLive:integer): Boolean; var HTTP: TIdHTTP; SSLHandler: TIdSSLIOHandlerSocketOpenSSL; ResponseStream: TStringStream; ResponseJSON: TJSONObject; StatusCode: Integer; ResponseText: string; begin Result := False; if Trim(TokenValue) = '' then begin Exit; end; HTTP := TIdHTTP.Create(nil); SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP); ResponseStream := TStringStream.Create; try HTTP.IOHandler := SSLHandler; HTTP.Request.CustomHeaders.Values['Authorization'] := 'OAuth ' + TokenValue; HTTP.Request.UserAgent := 'YourApp/1.0'; HTTP.Request.Accept := 'application/json'; HTTP.HTTPOptions := [hoKeepOrigProtocol]; try HTTP.Get('https://id.twitch.tv/oauth2/validate', ResponseStream); StatusCode := HTTP.ResponseCode; ResponseText := ResponseStream.DataString; except on E: EIdHTTPProtocolException do begin StatusCode := E.ErrorCode; ResponseText := E.ErrorMessage; end; on E: Exception do begin Exit; end; end; if StatusCode = 200 then begin try ResponseJSON := TJSONObject.ParseJSONValue(ResponseText) as TJSONObject; try if ResponseJSON.GetValue('expires_in') <> nil then begin //fLog.toLog(0, 'TokenCheck', TokenName, // Format('Токен действителен. Осталось: %d сек. Клиент: %s', // [ResponseJSON.GetValue('expires_in').Value.ToInteger, // ResponseJSON.GetValue('client_id').Value])); DayOfLive:=round(ResponseJSON.GetValue('expires_in').Value.ToInteger/60/60/24); end; Result := True; finally ResponseJSON.Free; end; except on E: Exception do //fLog.toLog(2, 'TokenCheck', 'JSON Parse', E.Message); end; end else if StatusCode = 401 then begin //fLog.toLog(2, 'TokenCheck', TokenName, 'Invalid token'); DayOfLive:=0; end else begin DayOfLive:=0; // fLog.toLog(2, 'TokenCheck', TokenName, // Format('HTTP %d: %s', [StatusCode, ResponseText])); end; finally ResponseStream.Free; SSLHandler.Free; HTTP.Free; end; end; procedure TTTW_API.warnUser(id: string); var RequestData: TStringStream; begin try if bot_id = '' then exit; if room_id = '' then exit; RequestData := TStringStream.Create('{"data": {"user_id":"' + id + '","reason":"Вам вынесено предупреждение!"}}', CP_UTF8); try postTTW('moderation/warnings?broadcaster_id=' + room_id + '&moderator_id=' + bot_id, ClientID, RequestData); finally RequestData.Free; end; except on E: Exception do //Form1.Log(2, 'TTTW_API.warnUser', E.Message); // flog.toLog(2,'TTW_API','warnUser',E.Message); end; end; // Вспомогательные функции для парсинга function GetStringValue(JSONObj: TJSONObject; const Name: string): string; var Val: TJSONValue; begin Val := JSONObj.GetValue(Name); if Assigned(Val) then Result := Val.Value else Result := ''; end; function GetStringArray(JSONObj: TJSONObject; const Name: string): TArray; var Arr: TJSONArray; I: Integer; begin SetLength(Result, 0); if not JSONObj.TryGetValue(Name, Arr) then Exit; SetLength(Result, Arr.Count); for I := 0 to Arr.Count - 1 do Result[I] := Arr.Items[I].Value; end; // Функция для преобразования JSON в список эмодзи procedure ParseEmotes(const JSONString: string; EmotesList: TEmotesList); var RootObj: TJSONObject; DataArr: TJSONArray; EmoteObj: TJSONObject; ImagesObj: TJSONObject; Emote: TEmotes; I: Integer; begin RootObj := TJSONObject.ParseJSONValue(JSONString) as TJSONObject; try if not RootObj.TryGetValue('data', DataArr) then Exit; for I := 0 to DataArr.Count - 1 do begin EmoteObj := DataArr.Items[I] as TJSONObject; // Заполняем основную информацию Emote.id := GetStringValue(EmoteObj, 'id'); Emote.name := GetStringValue(EmoteObj, 'name'); Emote.tier := GetStringValue(EmoteObj, 'tier'); Emote.emote_type := GetStringValue(EmoteObj, 'emote_type'); Emote.emote_set_id := GetStringValue(EmoteObj, 'emote_set_id'); // Парсим изображения if EmoteObj.TryGetValue('images', ImagesObj) then begin Emote.images.Url1x := GetStringValue(ImagesObj, 'url_1x'); Emote.images.Url2x := GetStringValue(ImagesObj, 'url_2x'); Emote.images.Url4x := GetStringValue(ImagesObj, 'url_4x'); end; // Парсим массивы Emote.format := GetStringArray(EmoteObj, 'format'); Emote.scale := GetStringArray(EmoteObj, 'scale'); Emote.theme_mode := GetStringArray(EmoteObj, 'theme_mode'); EmotesList.Add(Emote); end; finally RootObj.Free; end; end; procedure TTTW_API.GetChannelEmotes(var ce: Tlist); var jsonres:string; begin jsonres:=getTTW('chat/emotes?broadcaster_id='+room_id,ClientID,false); ParseEmotes(jsonres, ce); end; procedure TTTW_API.GetGlobalEmotes(var ge: Tlist); var jsonres:string; begin jsonres:=getTTW('chat/emotes/global',ClientID,false); ParseEmotes(jsonres, ge); end; end.