413 lines
10 KiB
ObjectPascal
413 lines
10 KiB
ObjectPascal
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
|
|
// Îáðàáîòêà 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;
|
|
|
|
// Îáðàáîòêà 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);
|
|
|
|
// Ïîëó÷åíèå áàçîâûõ äàííûõ
|
|
if Assigned(EmoteObj.GetValue('id')) then
|
|
Emote.id := EmoteObj.GetValue('id').Value;
|
|
if Assigned(EmoteObj.GetValue('name')) then
|
|
Emote.code := EmoteObj.GetValue('name').Value;
|
|
|
|
// Ïîëó÷åíèå 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);
|
|
|
|
// Ïîëó÷åíèå áàçîâûõ äàííûõ
|
|
if Assigned(EmoteObj.GetValue('id')) then
|
|
Emote.id := EmoteObj.GetValue('id').Value;
|
|
if Assigned(EmoteObj.GetValue('name')) then
|
|
Emote.code := EmoteObj.GetValue('name').Value;
|
|
|
|
// Ïîëó÷åíèå 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.
|