413 lines
10 KiB
Plaintext
413 lines
10 KiB
Plaintext
unit uCustomEmoties;
|
||
|
||
interface
|
||
|
||
uses
|
||
System.Classes, System.Generics.Collections, System.JSON, uRecords, IdHTTP, IdSSLOpenSSL,
|
||
System.Net.HttpClient, System.SysUtils;
|
||
|
||
type
|
||
TOnLog = procedure(aModul: string; aMethod: string; aMessage: string; aLevel: integer) of object;
|
||
|
||
|
||
type
|
||
TBTTV = class(TObject)
|
||
private
|
||
list: TList<TBTTVr>;
|
||
FOnLog: TOnLog;
|
||
procedure AddEmotesGlobalJson(const JsonStr: string);
|
||
procedure AddEmotesUserJson(const JsonStr: string);
|
||
function GetHTTP(aMethod: string): string;
|
||
procedure toLog(alevel: integer; amethod: string; amessage: string);
|
||
public
|
||
constructor Create;
|
||
destructor Destroy; override;
|
||
procedure GetGlobal;
|
||
procedure GetCustom(uid: string);
|
||
function GenerateURL(emoteName: string): string;
|
||
property OnLog: TOnLog read FOnLog write FOnLog;
|
||
end;
|
||
|
||
type
|
||
T7TV = class(TObject)
|
||
private
|
||
list7: TList<T7TVr>;
|
||
FOnLog: TOnLog;
|
||
procedure AddEmotesGlobalJson(const JsonStr: string);
|
||
procedure AddEmotesUserJson(const JsonStr: string);
|
||
function GetHTTP(aMethod: string): string;
|
||
public
|
||
constructor Create;
|
||
destructor Destroy; override;
|
||
procedure GetGlobal;
|
||
procedure GetCustom(uid: string);
|
||
function GenerateURL(emoteName: string): string;
|
||
procedure toLog(alevel: integer; amethod: string; amessage: string);
|
||
property OnLog: TOnLog read FOnLog write FOnLog;
|
||
end;
|
||
|
||
implementation
|
||
|
||
{ TBTTV }
|
||
|
||
constructor TBTTV.Create;
|
||
begin
|
||
inherited;
|
||
list := TList<TBTTVr>.Create;
|
||
end;
|
||
|
||
destructor TBTTV.Destroy;
|
||
begin
|
||
FreeAndNil(list);
|
||
inherited;
|
||
end;
|
||
|
||
procedure TBTTV.AddEmotesGlobalJson(const JsonStr: string);
|
||
var
|
||
JSONValue: TJSONValue;
|
||
JSONArray: TJSONArray;
|
||
EmoteObj: TJSONObject;
|
||
NewEmote: TBTTVr;
|
||
i: Integer;
|
||
begin
|
||
JSONValue := TJSONObject.ParseJSONValue(JsonStr);
|
||
if not Assigned(JSONValue) then Exit;
|
||
|
||
try
|
||
if not (JSONValue is TJSONArray) then Exit;
|
||
JSONArray := TJSONArray(JSONValue);
|
||
|
||
for i := 0 to JSONArray.Count - 1 do
|
||
begin
|
||
if not (JSONArray.Items[i] is TJSONObject) then Continue;
|
||
|
||
EmoteObj := TJSONObject(JSONArray.Items[i]);
|
||
NewEmote := Default(TBTTVr);
|
||
|
||
if Assigned(EmoteObj.GetValue('id')) then
|
||
NewEmote.id := EmoteObj.GetValue('id').Value;
|
||
if Assigned(EmoteObj.GetValue('code')) then
|
||
NewEmote.code := EmoteObj.GetValue('code').Value;
|
||
|
||
if not NewEmote.id.IsEmpty and not NewEmote.code.IsEmpty then
|
||
list.Add(NewEmote);
|
||
end;
|
||
finally
|
||
JSONValue.Free;
|
||
end;
|
||
end;
|
||
|
||
procedure TBTTV.AddEmotesUserJson(const JsonStr: string);
|
||
var
|
||
JSONValue, ChannelEmotes: TJSONValue;
|
||
JSONArray: TJSONArray;
|
||
EmoteObj: TJSONObject;
|
||
NewEmote: TBTTVr;
|
||
i: Integer;
|
||
begin
|
||
JSONValue := TJSONObject.ParseJSONValue(JsonStr);
|
||
if not Assigned(JSONValue) then Exit;
|
||
|
||
try
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> channelEmotes
|
||
ChannelEmotes := TJSONObject(JSONValue).GetValue('channelEmotes');
|
||
if (ChannelEmotes is TJSONArray) then
|
||
begin
|
||
JSONArray := TJSONArray(ChannelEmotes);
|
||
for i := 0 to JSONArray.Count - 1 do
|
||
begin
|
||
if not (JSONArray.Items[i] is TJSONObject) then Continue;
|
||
|
||
EmoteObj := TJSONObject(JSONArray.Items[i]);
|
||
NewEmote := Default(TBTTVr);
|
||
|
||
if Assigned(EmoteObj.GetValue('id')) then
|
||
NewEmote.id := EmoteObj.GetValue('id').Value;
|
||
if Assigned(EmoteObj.GetValue('code')) then
|
||
NewEmote.code := EmoteObj.GetValue('code').Value;
|
||
|
||
if not NewEmote.id.IsEmpty and not NewEmote.code.IsEmpty then
|
||
list.Add(NewEmote);
|
||
end;
|
||
end;
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> sharedEmotes
|
||
ChannelEmotes := TJSONObject(JSONValue).GetValue('sharedEmotes');
|
||
if (ChannelEmotes is TJSONArray) then
|
||
begin
|
||
JSONArray := TJSONArray(ChannelEmotes);
|
||
for i := 0 to JSONArray.Count - 1 do
|
||
begin
|
||
if not (JSONArray.Items[i] is TJSONObject) then Continue;
|
||
|
||
EmoteObj := TJSONObject(JSONArray.Items[i]);
|
||
NewEmote := Default(TBTTVr);
|
||
|
||
if Assigned(EmoteObj.GetValue('id')) then
|
||
NewEmote.id := EmoteObj.GetValue('id').Value;
|
||
if Assigned(EmoteObj.GetValue('code')) then
|
||
NewEmote.code := EmoteObj.GetValue('code').Value;
|
||
|
||
if not NewEmote.id.IsEmpty and not NewEmote.code.IsEmpty then
|
||
list.Add(NewEmote);
|
||
end;
|
||
end;
|
||
finally
|
||
JSONValue.Free;
|
||
end;
|
||
end;
|
||
|
||
function TBTTV.GenerateURL(emoteName: string): string;
|
||
var
|
||
emote: TBTTVr;
|
||
begin
|
||
Result := '';
|
||
for emote in list do
|
||
begin
|
||
if emote.code = emoteName then
|
||
begin
|
||
Result := 'https://cdn.betterttv.net/emote/' + emote.id + '/1x';
|
||
Exit;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure TBTTV.GetCustom(uid: string);
|
||
begin
|
||
if not uid.IsEmpty then
|
||
AddEmotesUserJson(GetHTTP('users/twitch/' + uid));
|
||
end;
|
||
|
||
procedure TBTTV.GetGlobal;
|
||
begin
|
||
AddEmotesGlobalJson(GetHTTP('emotes/global'));
|
||
end;
|
||
|
||
function TBTTV.GetHTTP(aMethod: string): string;
|
||
var
|
||
http: TIdHTTP;
|
||
ssl: TIdSSLIOHandlerSocketOpenSSL;
|
||
begin
|
||
Result := '';
|
||
|
||
try
|
||
http := TIdHTTP.Create(nil);
|
||
ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
|
||
try
|
||
http.IOHandler := ssl;
|
||
ssl.SSLOptions.SSLVersions := [sslvTLSv1_2];
|
||
http.Request.UserAgent :=
|
||
'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
||
Result := http.Get('https://api.betterttv.net/3/cached/' + aMethod);
|
||
finally
|
||
ssl.Free;
|
||
http.Free;
|
||
end;
|
||
except
|
||
on E: Exception do
|
||
begin
|
||
toLog(2,'GetCustom',e.Message);
|
||
Result := '';
|
||
end;
|
||
end;
|
||
|
||
end;
|
||
|
||
procedure TBTTV.toLog(alevel: integer; amethod, amessage: string);
|
||
begin
|
||
if Assigned(FOnLog) then
|
||
FOnLog('uCustomEmoties.TBTTV', amethod, amessage, alevel);
|
||
end;
|
||
|
||
{ T7TV }
|
||
|
||
constructor T7TV.Create;
|
||
begin
|
||
inherited;
|
||
list7 := TList<T7TVr>.Create;
|
||
end;
|
||
|
||
destructor T7TV.Destroy;
|
||
begin
|
||
FreeAndNil(list7);
|
||
inherited;
|
||
end;
|
||
|
||
procedure T7TV.AddEmotesGlobalJson(const JsonStr: string);
|
||
var
|
||
Root: TJSONObject;
|
||
EmotesArray: TJSONArray;
|
||
EmoteObj, DataObj, HostObj: TJSONObject;
|
||
FilesArray: TJSONArray;
|
||
i: Integer;
|
||
Emote: T7TVr;
|
||
BaseUrl: string;
|
||
begin
|
||
Root := TJSONObject.ParseJSONValue(JsonStr) as TJSONObject;
|
||
if not Assigned(Root) then Exit;
|
||
|
||
try
|
||
EmotesArray := Root.GetValue('emotes') as TJSONArray;
|
||
if not Assigned(EmotesArray) then Exit;
|
||
|
||
for i := 0 to EmotesArray.Count - 1 do
|
||
begin
|
||
if not (EmotesArray.Items[i] is TJSONObject) then Continue;
|
||
|
||
EmoteObj := EmotesArray.Items[i] as TJSONObject;
|
||
Emote := Default(T7TVr);
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if Assigned(EmoteObj.GetValue('id')) then
|
||
Emote.id := EmoteObj.GetValue('id').Value;
|
||
if Assigned(EmoteObj.GetValue('name')) then
|
||
Emote.code := EmoteObj.GetValue('name').Value;
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> URL
|
||
DataObj := EmoteObj.GetValue('data') as TJSONObject;
|
||
if Assigned(DataObj) then
|
||
begin
|
||
HostObj := DataObj.GetValue('host') as TJSONObject;
|
||
if Assigned(HostObj) then
|
||
begin
|
||
if Assigned(HostObj.GetValue('url')) then
|
||
begin
|
||
BaseUrl := 'https:' + HostObj.GetValue('url').Value;
|
||
|
||
FilesArray := HostObj.GetValue('files') as TJSONArray;
|
||
if Assigned(FilesArray) and (FilesArray.Count > 0) and
|
||
(FilesArray.Items[0] is TJSONObject) then
|
||
begin
|
||
Emote.url := BaseUrl + '/' +
|
||
(FilesArray.Items[0] as TJSONObject).GetValue('name').Value;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if not Emote.id.IsEmpty and not Emote.code.IsEmpty and not Emote.url.IsEmpty then
|
||
list7.Add(Emote);
|
||
end;
|
||
finally
|
||
Root.Free;
|
||
end;
|
||
end;
|
||
|
||
procedure T7TV.AddEmotesUserJson(const JsonStr: string);
|
||
var
|
||
Root, EmoteSet, EmoteObj, DataObj, HostObj: TJSONObject;
|
||
EmotesArr, FilesArr: TJSONArray;
|
||
i: Integer;
|
||
Emote: T7TVr;
|
||
BaseUrl: string;
|
||
begin
|
||
Root := TJSONObject.ParseJSONValue(JsonStr) as TJSONObject;
|
||
if not Assigned(Root) then Exit;
|
||
|
||
try
|
||
if not Root.TryGetValue<TJSONObject>('emote_set', EmoteSet) then Exit;
|
||
|
||
EmotesArr := EmoteSet.GetValue('emotes') as TJSONArray;
|
||
if not Assigned(EmotesArr) then Exit;
|
||
|
||
for i := 0 to EmotesArr.Count - 1 do
|
||
begin
|
||
if not (EmotesArr.Items[i] is TJSONObject) then Continue;
|
||
|
||
EmoteObj := EmotesArr.Items[i] as TJSONObject;
|
||
Emote := Default(T7TVr);
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if Assigned(EmoteObj.GetValue('id')) then
|
||
Emote.id := EmoteObj.GetValue('id').Value;
|
||
if Assigned(EmoteObj.GetValue('name')) then
|
||
Emote.code := EmoteObj.GetValue('name').Value;
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> URL
|
||
DataObj := EmoteObj.GetValue('data') as TJSONObject;
|
||
if Assigned(DataObj) then
|
||
begin
|
||
HostObj := DataObj.GetValue('host') as TJSONObject;
|
||
if Assigned(HostObj) then
|
||
begin
|
||
if Assigned(HostObj.GetValue('url')) then
|
||
begin
|
||
BaseUrl := 'https:' + HostObj.GetValue('url').Value;
|
||
|
||
FilesArr := HostObj.GetValue('files') as TJSONArray;
|
||
if Assigned(FilesArr) and (FilesArr.Count > 0) and
|
||
(FilesArr.Items[0] is TJSONObject) then
|
||
begin
|
||
Emote.url := BaseUrl + '/' +
|
||
(FilesArr.Items[0] as TJSONObject).GetValue('name').Value;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if not Emote.id.IsEmpty and not Emote.code.IsEmpty and not Emote.url.IsEmpty then
|
||
list7.Add(Emote);
|
||
end;
|
||
finally
|
||
Root.Free;
|
||
end;
|
||
end;
|
||
|
||
function T7TV.GenerateURL(emoteName: string): string;
|
||
var
|
||
emote: T7TVr;
|
||
begin
|
||
Result := '';
|
||
for emote in list7 do
|
||
begin
|
||
if emote.code = emoteName then
|
||
begin
|
||
Result := emote.url;
|
||
Exit;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure T7TV.GetCustom(uid: string);
|
||
begin
|
||
if not uid.IsEmpty then
|
||
AddEmotesUserJson(GetHTTP('users/twitch/' + uid));
|
||
end;
|
||
|
||
procedure T7TV.GetGlobal;
|
||
begin
|
||
AddEmotesGlobalJson(GetHTTP('emote-sets/global'));
|
||
end;
|
||
|
||
function T7TV.GetHTTP(aMethod: string): string;
|
||
var
|
||
HttpClient: THTTPClient;
|
||
Response: IHTTPResponse;
|
||
begin
|
||
Result := '';
|
||
HttpClient := THTTPClient.Create;
|
||
try
|
||
try
|
||
HttpClient.UserAgent := 'Mozilla/5.0';
|
||
Response := HttpClient.Get('https://api.7tv.app/v3/' + aMethod);
|
||
Result := Response.ContentAsString;
|
||
except
|
||
on E: Exception do
|
||
begin
|
||
toLog(2,'GetHTTP',e.Message);
|
||
Result := '';
|
||
end;
|
||
end;
|
||
finally
|
||
HttpClient.Free;
|
||
end;
|
||
end;
|
||
|
||
procedure T7TV.toLog(alevel: integer; amethod, amessage: string);
|
||
begin
|
||
if Assigned(FOnLog) then
|
||
FOnLog('uCustomEmoties.T7TV', amethod, amessage, alevel);
|
||
end;
|
||
|
||
end.
|