You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RnQ/RnQ/ICQ/Stickers.pas

306 lines
8.4 KiB
Plaintext

unit Stickers;
{$I forRnQConfig.inc}
interface
uses
System.Classes, System.SysUtils, System.JSON, Generics.Collections;
{$I PubRTTI.inc}
type
PStickerPack = ^TStickerPack;
TStickerPack = record
Id: Integer;
StoreId: String;
Name: String;
Desc: String;
ListIconLink: String;
Content: TArray;
ContentType: String;
Keywords: TArray;
Purchased: Boolean;
UserSticker: Boolean;
IsEnabled: Boolean;
Priority: Integer;
Count: Integer;
_IsDefault: Boolean;
class function FromJSON(const JSON: TJSONObject): TStickerPack; static;
end;
TStickerPacks = TArray;
TStickerIDType = (SIDT_ID = 0, SIDT_STOREID = 1, SIDT_FILEID = 2);
{$I NoRTTI.inc}
function GetSticker(const FileID: String; pifs: TMemoryStream = nil; const ForceSize: String = ''): TBytes;
function GetAnimatedSticker(const FileID: String; pifs: TMemoryStream = nil; IsPicker: Boolean = False): TBytes;
function GetStickerPackContent(const Id: String): TArray;
// function CheckStickerCache(Ext, Sticker: Integer; const ForceSize: String = ''): Boolean;
// function GetCachedStickers: String;
function GetCachedPickers: String;
procedure RemoveStickerPackCache(const PackId: String);
var
DupStickerPacks: TList;
implementation
uses
System.StrUtils, RnQGlobal, RnQNet, SQLiteDB, globalLib, utilLib, ICQConsts;
function GetSticker(const FileID: String; pifs: TMemoryStream = nil; const ForceSize: String = ''): TBytes;
var
URL, Size: String;
fn: String;
fs: TMemoryStream;
begin
if pifs = nil then
fs := TMemoryStream.Create
else
fs := pifs;
if not (ForceSize = '') then
Size := ForceSize
else
Size := 'sticker_small';
URL := BIN_PREVIEW_HOST + Size + '/' + FileID;
fn := StickerPath + FileID + '_' + Size + '.webp';
if not FileExists(fn) then
begin
if not DirectoryExists(StickerPath) then
ForceDirectories(StickerPath);
LoadFromURLAsFile(URL, fn);
end;
if FileExists(fn) then
fs.LoadFromFile(fn);
fs.Seek(0, 0);
SetLength(Result, fs.size);
fs.ReadBuffer(Result, fs.size);
if pifs = nil then
fs.Free
else
fs.Seek(0, 0);
end;
function GetAnimatedSticker(const FileID: String; pifs: TMemoryStream = nil; IsPicker: Boolean = False): TBytes;
var
URL: String;
fn: String;
fs: TMemoryStream;
begin
if pifs = nil then
fs := TMemoryStream.Create
else
fs := pifs;
if IsPicker then
begin
URL := LOTTIE_PREVIEW_HOST + 'stickerpicker_small/' + FileID;
fn := StickerPath + FileID + '_stickerpicker_small.webp'; // It's actually PNG
end
else
begin
URL := LOTTIE_ORIGINAL_HOST + FileID;
fn := StickerPath + FileID + '_original.json';
end;
if not FileExists(fn) then
begin
if not DirectoryExists(StickerPath) then
ForceDirectories(StickerPath);
LoadFromURLAsFile(URL, fn);
end;
if FileExists(fn) then
fs.LoadFromFile(fn);
fs.Seek(0, 0);
SetLength(Result, fs.size);
fs.ReadBuffer(Result, fs.size);
if pifs = nil then
fs.Free
else
fs.Seek(0, 0);
end;
function GetStickerPackContent(const Id: String): TArray;
var
SRecord: TStickerPack;
begin
Result := SQLDB.GetStickerPackContent(Id);
if Length(Result) = 0 then
begin
SRecord := Account.AccProto.GetStoreStickerPackInfo(Id);
if not SRecord._IsDefault then
begin
SQLDB.AddStickerPack(SRecord);
Result := SRecord.Content;
end;
end;
end;
procedure RemoveStickerPackCache(const PackId: String);
var
sr: TSearchRec;
begin
if FindFirst(StickerPath + PackId + '_*_*.webp', faAnyFile, sr) = 0 then
repeat
if not (sr.name = '.') and not (sr.name = '..') then
DeleteFile(StickerPath + sr.name);
until FindNext(sr) <> 0;
FindClose(sr);
end;
{
function CheckStickerCache(Ext, Sticker: Integer; const ForceSize: String = ''): Boolean;
var
Size: String;
fn: String;
begin
if not (ForceSize = '') then
Size := ForceSize
else
case StickerResolution of
0:
Size := 'small';
1:
Size := 'medium';
2:
Size := 'large';
end;
fn := StickerPath + IntToStr(Ext) + '_' + IntToStr(Sticker) + '_' + Size + '.png';
Result := FileExists(fn);
end;
function GetCachedStickers: String;
var
i, j: Integer;
begin
Result := '';
for i := 0 to Length(StickerCats) - 1 do
for j := 1 to StickerCatCounts[i] do
if CheckStickerCache(StickerCats[i], j, 'small') then
Result := Result + 'sticker:n' + IntToStr(StickerCats[i]) + '_' + IntToStr(j) + #10;
Result := Trim(Result);
end;
}
function CheckPickerCache(const FileID: String): Boolean;
begin
Result := FileExists(StickerPath + FileID + '_stickerpicker_small.webp');
end;
function GetCachedPickers: String;
var
I: Integer;
Packs: TStickerPacks;
begin
Result := '';
Packs := SQLDB.GetStickerPacks(True);
for I := 0 to Length(Packs) - 1 do
if (Length(Packs[i].Content) > 0) and CheckPickerCache(Packs[i].Content[0]) then
Result := Result + IfThen(Packs[i].ContentType = 'animated', 'picker:a', 'picker:n') + Packs[i].Content[0] + #10;
Result := Trim(Result);
end;
class function TStickerPack.FromJSON(const JSON: TJSONObject): TStickerPack;
var
FileIDs, TmpVal: TJSONValue;
TmpArr: TJSONArray;
PickerIcon, TmpStr: String;
begin
Result := Default(TStickerPack);
Result._IsDefault := True;
with JSON do
begin
GetValueSafe('id', Result.Id);
GetValueSafe('store_id', Result.StoreId);
GetValueSafe('name', Result.Name);
GetValueSafe('description', Result.Desc);
GetValueSafe('count', Result.Count);
GetValueSafe('purchased', Result.Purchased);
if not GetValueSafe('usersticker', Result.UserSticker) then
GetValueSafe('user_sticker', Result.UserSticker);
GetValueSafe('priority', Result.Priority);
GetValueSafe('is_enabled', Result.IsEnabled);
try
TmpVal := GetValue('list_icons');
if (TmpVal is TJSONObject) then
TmpVal.GetValueSafe('small', Result.ListIconLink)
else if (TmpVal is TJSONString) then
Result.ListIconLink := TmpVal.Value;
if (Result.ListIconLink = '') then
if (GetValue('list_icon') is TJSONString) then
GetValueSafe('list_icon', Result.ListIconLink);
if (Result.ListIconLink = '') then
begin
TmpVal := GetValue('icons');
if TmpVal is TJSONObject then
TmpVal.GetValueSafe('small', Result.ListIconLink)
else if TmpVal is TJSONString then
Result.ListIconLink := TmpVal.Value;
end;
if (Result.ListIconLink = '') then
if GetValue('icon') is TJSONString then
GetValueSafe('icon', Result.ListIconLink);
except end;
if not GetValueSafe('type', Result.ContentType) then
begin
PickerIcon := '';
if not GetValueSafe('sticker_picker_icon', PickerIcon) then
GetValueSafe('contentlist_sticker_picker_icon', PickerIcon);
Result.ContentType := IfThen(PickerIcon.Contains('api/v1/files/sticker'), 'animated', 'image');
end;
SetLength(Result.Content, 0);
SetLength(Result.Keywords, 0);
FileIDs := JSON.GetValue('content');
if (FileIDs is TJSONArray) then
for var FileID in TJSONArray(FileIDs) do
if FileID is TJSONString then
Result.Content := Result.Content + [FileID.Value]
else if FileID is TJSONObject then
begin
TmpStr := '';
FileID.GetValueSafe('fileId', TmpStr);
if TmpStr = '' then
Continue;
Result.Content := Result.Content + [TmpStr];
TmpStr := '';
TmpArr := TJSONObject(FileID).GetValue('emoji') as TJSONArray;
if TmpArr is TJSONArray then
for TmpVal in TmpArr do
TmpStr := TmpStr + ' ' + TmpVal.Value;
TmpArr := TJSONObject(FileID).GetValue('words') as TJSONArray;
if TmpArr is TJSONArray then
for TmpVal in TmpArr do
TmpStr := TmpStr + ' ∙ ' + TmpVal.Value;
Result.Keywords := Result.Keywords + [TmpStr.Trim([' ', '∙'])];
end;
end;
Result._IsDefault := False;
end;
initialization
DupStickerPacks := TList.Create;
DupStickerPacks.AddRange([116288, 194855, 234247 {Cute Pigs - Incomplete set}]);
finalization
DupStickerPacks.Free;
end.