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.
306 lines
8.4 KiB
Plaintext
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 |
|
DupStickerPacks.AddRange([116288, 194855, 234247 {Cute Pigs - Incomplete set}]);
|
|
|
|
finalization
|
|
|
|
DupStickerPacks.Free;
|
|
|
|
end.
|