gamedownloader/downloader.pas

223 lines
5.3 KiB
ObjectPascal

program downloader;
uses fphttpclient, base64, opensslsockets, fpjson, jsonparser, SysUtils, process, Classes, libtar, CustApp, Math;
var
gameId: Integer;
gameData: TJSONData;
client: TFPHTTPClient;
authString, tarFile, errorMsg: String;
app: TCustomApplication;
procedure createFileDir(filePath: AnsiString);
var
splitDir: TStringArray;
s: String;
newDir: String = '';
begin
splitDir := filePath.Split(['\', '/']);
for s in splitDir do
begin
if not (s = splitDir[Length(splitDir)-1]) then
begin
newDir := newDir + s + '/';
CreateDir(newDir);
end;
end;
end;
procedure copyFile(oldFile, newFile: AnsiString);
var
source, dest: TFileStream;
begin
createFileDir(newFile);
source := TFileStream.Create(oldFile, fmOpenRead);
dest := TFileStream.Create(newFile, fmCreate);
dest.CopyFrom(source, source.Size);
source.Free;
dest.Free;
end;
function getGameData(var client: TFPHTTPClient; gameId: Integer; out gameData: TJSONData): Boolean;
const
url = 'https://rpi.narnian.us/games/get_game/';
var
jData: TJSONData;
begin
writeln('start get game data');
client.AllowRedirect := true;
try
jData := GetJSON(client.Get(url+IntToStr(gameId)));
gameData := jData;
getGameData := true;
Except
getGameData := false;
end;
end;
function downloadGameTar(var client: TFPHTTPClient; gameId: Integer): String;
const
url = 'https://rpi.narnian.us/games/download/windows/';
var
tarFile: TFileStream;
tarFileName: String;
begin
writeln('start download tar');
client.AllowRedirect := true;
tarFileName := gameData.FindPath('title_sanitized').AsString+'.tar';
tarFile := TFileStream.Create(tarFileName, fmCreate);
client.Get(url+IntToStr(gameId), tarFile);
tarFile.Free;
downloadGameTar := tarFileName;
end;
procedure extractTar(fileName: String);
var
tarFile: TTarArchive;
tarContent: TTarDirRec;
files: TJSONArray;
firstFile: String;
i: Integer;
begin
writeln('start extract tar');
tarFile := TTarArchive.Create(fileName);
while tarFile.FindNext(tarContent) do
begin
files := TJSONArray(gameData.FindPath('windows.files.'+tarContent.Name));
firstFile := files.Strings[0];
createFileDir(firstFile);
tarFile.ReadFile(firstFile);
for i := 1 to files.Count-1 do
begin
createFileDir(files.Strings[i]);
copyFile(firstFile, files.Strings[i]);
end;
end;
tarFile.Destroy;
end;
function authenticate(client: TFPHTTPClient): Boolean;
const
url = 'https://rpi.narnian.us';
var
username, password: String;
begin
if app.HasOption('u', 'user') then
begin
username := app.GetOptionValue('u', 'username');
end
else
begin
Write('Enter username: ');
ReadLn(username);
end;
if app.HasOption('p', 'password') then
begin
password := app.GetOptionValue('p', 'password');
end
else
begin
Write('Enter password: ');
ReadLn(password);
end;
authString := username + ':' + password;
client.AddHeader('Authorization', 'Basic '+base64.EncodeStringBase64(authString));
client.AllowRedirect := true;
try
client.Get(url);
authenticate := true;
except
authenticate := false;
end;
end;
procedure displayHelp;
const
optionFlags: TStringArray = (
'-h, --help',
'-g, --gameid <game id>',
'-u, --username <username>',
'-p, --password <password>');
optionDescriptions: TStringArray = (
'Display help.',
'Sets the game id. This is required.',
'Sets the username for authentication.',
'Sets the password for authentication.');
var
i, lenFlag, lenDesc, maxLenFlag, maxLenDesc, minLenFlag, minLenDesc: Integer;
begin
maxLenFlag := 0;
maxLenDesc := 0;
minLenFlag := 1000;
minLenDesc := 1000;
for i := 0 to Length(optionFlags)-1 do
begin
minLenFlag := Min(minLenFlag, Length(optionFlags[i]));
maxLenFlag := Max(maxLenFlag, Length(optionFlags[i]));
minLenDesc := Min(minLenDesc, Length(optionDescriptions[i]));
maxLenDesc := Max(maxLenDesc, Length(optionDescriptions[i]));
end;
WriteLn('Usage: downloader.exe [options]');
WriteLn;
WriteLn('Options:');
for i := 0 to Length(optionFLags)-1 do
begin
lenFlag := Length(optionFLags[i]);
lenDesc := Length(optionDescriptions[i]);
Write(optionFlags[i]:(lenFlag+2));
WriteLn(optionDescriptions[i]:(lenDesc+maxLenFlag-lenFlag+2))
end;
end;
begin
app := TCustomApplication.Create(nil);
errorMsg := app.checkOptions('hg:u:p:', 'help gameid: username: password:');
if (errorMsg <> '') or app.HasOption('h', 'help') then
begin
WriteLn(errorMsg);
displayHelp;
end
else
begin
if app.HasOption('g', 'gameid') then
begin
gameId := StrToInt(app.GetOptionValue('g', 'gameid'));
client := TFPHTTPClient.Create(nil);
if authenticate(client) then
begin
if getGameData(client, gameId, gameData) then
begin
tarFile := downloadGameTar(client, gameId);
extractTar(tarFile);
DeleteFile(tarFile);
WriteLn('Download finished');
end
else
begin
WriteLn('Invalid game id given');
end;
end
else
begin
WriteLn('Invalid username or password');
end;
end
else
begin
WriteLn('No game id was given');
end;
end;
end.