Skip to content

Commit

Permalink
Update Humble Trove support (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
tkashkin committed Dec 21, 2018
1 parent 28e6f8d commit 9d040db
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 150 deletions.
167 changes: 108 additions & 59 deletions src/data/sources/humble/HumbleGame.vala
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,46 @@ namespace GameHub.Data.Sources.Humble
var json_obj = json_node.get_object();

id = json_obj.get_string_member("machine_name");
name = json_obj.get_string_member("human_name");
image = json_obj.get_string_member("icon");
icon = image;
name = json_obj.has_member("human_name") ? json_obj.get_string_member("human_name") : json_obj.get_string_member("human-name");
image = json_obj.has_member("image") ? json_obj.get_string_member("image") : json_obj.get_string_member("icon");
icon = json_obj.has_member("icon") ? json_obj.get_string_member("icon") : image;
order_id = order;

info = Json.to_string(json_node, false);

platforms.clear();
if(json_obj.has_member("downloads") && json_obj.get_member("downloads").get_node_type() == Json.NodeType.ARRAY)

if(json_obj.has_member("downloads"))
{
foreach(var dl in json_obj.get_array_member("downloads").get_elements())
var downloads_node = json_obj.get_member("downloads");
switch(downloads_node.get_node_type())
{
var pl = dl.get_object().get_string_member("platform");
foreach(var p in Platforms)
{
if(pl == p.id())
case Json.NodeType.ARRAY:
foreach(var dl in downloads_node.get_array().get_elements())
{
platforms.add(p);
var dl_platform = dl.get_object().get_string_member("platform");
foreach(var p in Platforms)
{
if(dl_platform == p.id())
{
platforms.add(p);
}
}
}
}
break;

case Json.NodeType.OBJECT:
foreach(var dl_platform in downloads_node.get_object().get_members())
{
foreach(var p in Platforms)
{
if(dl_platform == p.id())
{
platforms.add(p);
}
}
}
break;
}
}

Expand Down Expand Up @@ -193,67 +213,58 @@ namespace GameHub.Data.Sources.Humble
var product = Parser.parse_json(info).get_object();
if(product == null) return;

if(product.has_member("_gamehub_description"))
if(product.has_member("description-text"))
{
description = product.get_string_member("description-text");
}
else if(product.has_member("_gamehub_description"))
{
description = product.get_string_member("_gamehub_description");
}

if(product.has_member("downloads") && product.get_member("downloads").get_node_type() == Json.NodeType.ARRAY)
if(product.has_member("downloads"))
{
foreach(var dl_node in product.get_array_member("downloads").get_elements())
{
var dl = dl_node.get_object();
var id = dl.get_string_member("machine_name");
var dl_id = dl.has_member("download_identifier") ? dl.get_string_member("download_identifier") : null;
var os = dl.get_string_member("platform");
var platform = CurrentPlatform;
foreach(var p in Platforms)
{
if(os == p.id())
{
platform = p;
break;
}
}

bool refresh = false;
bool refresh = false;

if(dl.has_member("download_struct") && dl.get_member("download_struct").get_node_type() == Json.NodeType.ARRAY)
{
foreach(var dls_node in dl.get_array_member("download_struct").get_elements())
var downloads_node = product.get_member("downloads");
switch(downloads_node.get_node_type())
{
case Json.NodeType.ARRAY:
foreach(var dl_node in downloads_node.get_array().get_elements())
{
var installer = new Installer(this, id, dl_id, platform, dls_node.get_object());
if(installer.is_url_update_required())
var dl = dl_node.get_object();
var id = dl.get_string_member("machine_name");
var dl_id = dl.has_member("download_identifier") ? dl.get_string_member("download_identifier") : null;
var os = dl.get_string_member("platform");
if(dl.has_member("download_struct") && dl.get_member("download_struct").get_node_type() == Json.NodeType.ARRAY)
{
if(source is Trove)
foreach(var dls_node in dl.get_array_member("download_struct").get_elements())
{
var old_url = installer.part.url;
var new_url = installer.update_url(this);
if(new_url != null)
{
info = info.replace(old_url, new_url);
}
refresh = true;
}
else
{
info = null;
refresh = true;
refresh = process_download(id, dl_id, os, dls_node.get_object());
}
}
if(!refresh) installers.add(installer);
}
}
break;

if(refresh && !game_info_refreshed)
{
//debug("[HumbleGame.update_game_info] Refreshing");
game_info_refreshed = true;
game_info_updated = false;
installers.clear();
yield update_game_info();
return;
}
case Json.NodeType.OBJECT:
foreach(var os in downloads_node.get_object().get_members())
{
var dl = downloads_node.get_object().get_object_member(os);
var id = dl.get_string_member("machine_name");
var dl_id = dl.has_member("download_identifier") ? dl.get_string_member("download_identifier") : null;
refresh = process_download(id, dl_id, os, dl);
}
break;
}

if(refresh && !game_info_refreshed)
{
//debug("[HumbleGame.update_game_info] Refreshing");
game_info_refreshed = true;
game_info_updated = false;
installers.clear();
yield update_game_info();
return;
}
}

Expand All @@ -264,6 +275,44 @@ namespace GameHub.Data.Sources.Humble
game_info_updated = true;
}

private bool process_download(string id, string? dl_id, string os, Json.Object dl_struct)
{
var platform = CurrentPlatform;
foreach(var p in Platforms)
{
if(os == p.id())
{
platform = p;
break;
}
}

bool refresh = false;

var installer = new Installer(this, id, dl_id, platform, dl_struct);
if(installer.is_url_update_required())
{
if(source is Trove)
{
var old_url = installer.part.url;
var new_url = installer.update_url(this);
if(new_url != null)
{
info = info.replace(old_url, new_url);
}
refresh = true;
}
else
{
info = null;
refresh = true;
}
}
if(!refresh) installers.add(installer);

return refresh;
}

public override async void install()
{
yield update_game_info();
Expand Down
112 changes: 24 additions & 88 deletions src/data/sources/humble/Trove.vala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace GameHub.Data.Sources.Humble
public const string PAGE_URL = "https://www.humblebundle.com/monthly/trove";
public const string SIGN_URL = "https://www.humblebundle.com/api/v1/user/download/sign";
public const string FAKE_ORDER = "humble-trove";
public const string TROVE_INTRO_ID = "trove_intro";

public override string id { get { return "humble-trove"; } }
public override string name { get { return "Humble Trove"; } }
Expand Down Expand Up @@ -89,100 +90,35 @@ namespace GameHub.Data.Sources.Humble
{
var xpath = new Xml.XPath.Context(html);

var items = xpath.eval("//div[starts-with(@class, 'trove-grid-item')]")->nodesetval;
if(items != null && !items->is_empty())
{
for(int i = 0; i < items->length(); i++)
{
var item = items->item(i);
var id = item->get_prop("data-machine-name");
var xr = @"//div[starts-with(@class, 'trove-product-detail')][@data-machine-name='$(id)']";

var dl_btn = xpath.eval(@"$(xr)//button[contains(@class, 'js-download-button')]")->nodesetval;

if(dl_btn == null || dl_btn->is_empty())
{
continue; // no dl button, can't download
}

var image = Parser.html_subnode(item, "img")->get_prop("src");

var name = xpath.eval(@"$(xr)//h1[@class='product-human-name']/text()")->nodesetval->item(0)->content;

var desc_nodes = xpath.eval(@"$(xr)//div[@class='trove-product-description']/node()")->nodesetval;

string desc = "";

if(desc_nodes != null && desc_nodes->length() > 0)
{
for(int dn = 0; dn < desc_nodes->length(); dn++)
{
desc += Parser.xml_node_to_string(desc_nodes->item(dn));
}
desc = desc.strip();
}
var trove_json = xpath.eval("//script[@id='webpack-monthly-trove-data']/text()")->nodesetval->item(0)->content.strip();

var json = new Json.Object();
json.set_string_member("machine_name", id);
json.set_string_member("human_name", name);
json.set_string_member("icon", image);
json.set_string_member("_gamehub_description", desc);
if(trove_json != null)
{
var trove_root_node = Parser.parse_json(trove_json);
var trove_root = Parser.json_object(trove_root_node, { "displayItemData" });

var dl_nodes = xpath.eval(@"$(xr)//div[starts-with(@class, 'trove-platform-selector')]")->nodesetval;
if(trove_root != null)
{
trove_root.foreach_member((trove_root_obj, key, node) => {
if(key == TROVE_INTRO_ID) return;

var dls = new Json.Array();
var game = new HumbleGame(this, Trove.FAKE_ORDER, node);

if(dl_nodes != null && !dl_nodes->is_empty())
{
for(int d = 0; d < dl_nodes->length(); d++)
if(game.platforms.size == 0) return;
bool is_new_game = !_games.contains(game);
if(is_new_game && (!Settings.UI.get_instance().merge_games || !Tables.Merges.is_game_merged(game)))
{
var dn = dl_nodes->item(d);
var dl = new Json.Object();

dl.set_string_member("platform", dn->get_prop("data-platform"));
dl.set_string_member("download_identifier", dn->get_prop("data-url"));
dl.set_string_member("machine_name", dn->get_prop("data-machine-name"));

var signed_url = sign_url(dn->get_prop("data-machine-name"), dn->get_prop("data-url"), user_token);

var dl_struct = new Json.Object();
dl_struct.set_string_member("name", @"$(name) (Trove)");

var urls = new Json.Object();
urls.set_string_member("web", signed_url);

dl_struct.set_object_member("url", urls);

var dl_struct_arr = new Json.Array();
dl_struct_arr.add_object_element(dl_struct);

dl.set_array_member("download_struct", dl_struct_arr);

dls.add_object_element(dl);
game.update_game_info.begin((obj, res) => {
game.update_game_info.end(res);
_games.add(game);
if(game_loaded != null)
{
Idle.add(() => { game_loaded(game, false); return Source.REMOVE; });
}
});
}
}

json.set_array_member("downloads", dls);

var json_node = new Json.Node(Json.NodeType.OBJECT);
json_node.set_object(json);

var game = new HumbleGame(this, Trove.FAKE_ORDER, json_node);

if(game.platforms.size == 0) continue;
bool is_new_game = !_games.contains(game);
if(is_new_game && (!Settings.UI.get_instance().merge_games || !Tables.Merges.is_game_merged(game)))
{
game.update_game_info.begin((obj, res) => {
game.update_game_info.end(res);
_games.add(game);
if(game_loaded != null)
{
Idle.add(() => { game_loaded(game, false); return Source.REMOVE; });
}
});
}
if(is_new_game) games_count++;
if(is_new_game) games_count++;
});
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/utils/downloader/Downloader.vala
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ namespace GameHub.Utils.Downloader
return downloader;
}

public abstract async File download(File remote, File local, DownloadInfo? info=null, bool preserve_filename=true) throws Error;
public abstract async File? download(File remote, File local, DownloadInfo? info=null, bool preserve_filename=true) throws Error;
public abstract Download? get_download(File remote);
}

public static async File download(File remote, File local, DownloadInfo? info=null, bool preserve_filename=true) throws Error
public static async File? download(File remote, File local, DownloadInfo? info=null, bool preserve_filename=true) throws Error
{
File result = local;
Error? error = null;
Expand Down
5 changes: 4 additions & 1 deletion src/utils/downloader/SoupDownloader.vala
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ namespace GameHub.Utils.Downloader.Soup
return downloads.get(remote.get_uri());
}

public override async File download(File remote, File local, DownloadInfo? info=null, bool preserve_filename=true) throws Error
public override async File? download(File remote, File local, DownloadInfo? info=null, bool preserve_filename=true) throws Error
{
if(remote == null || remote.get_uri() == null || remote.get_uri().length == 0) return null;

var uri = remote.get_uri();
SoupDownload download = downloads.get(uri);

Expand Down Expand Up @@ -302,6 +304,7 @@ namespace GameHub.Utils.Downloader.Soup

private async void download_from_filesystem(SoupDownload download) throws GLib.Error
{
if(download.remote == null || !download.remote.query_exists()) return;
try
{
debug("[SoupDownloader] Copying '%s' to '%s'", download.remote.get_path(), download.local_tmp.get_path());
Expand Down

0 comments on commit 9d040db

Please sign in to comment.