From 077f74cd2b9ad84732de2809e66fa8862a277482 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Sun, 14 Nov 2021 13:23:57 -0600 Subject: [PATCH] Games page back to semi-functional; games are out of order however --- .gitignore | 3 ++ data/cache/.gitkeep | 0 lib/api.rb | 11 +++++ lib/api/applications.rb | 6 ++- lib/api/news.rb | 32 +++++++++++++ lib/pages/games.rb | 102 ++++++++++++++++++++++++++-------------- lib/states/boot.rb | 28 +++++------ lib/states/interface.rb | 1 + w3dhub.rb | 28 ++++++----- 9 files changed, 145 insertions(+), 66 deletions(-) create mode 100644 .gitignore create mode 100644 data/cache/.gitkeep create mode 100644 lib/api/news.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..384784c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.json +data/cache/* +!data/cache/.gitkeep \ No newline at end of file diff --git a/data/cache/.gitkeep b/data/cache/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/api.rb b/lib/api.rb index 5f9e8a0..950ebaf 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -76,6 +76,17 @@ class W3DHub # Client requests news for a specific application/game e.g.: data={"category":"ia"} # Response is a JSON hash with a "highlighted" and "news" keys; the "news" on seems to be the desired one def self.news(category) + response = W3DHUB_API_CONNECTION.post( + path: "apis/w3dhub/1/get-news", + headers: DEFAULT_HEADERS.merge({"Content-Type": "application/x-www-form-urlencoded"}), + body: "data=#{JSON.dump({category: category})}" + ) + + if response.status == 200 + News.new(response.body) + else + false + end end # Downloading games diff --git a/lib/api/applications.rb b/lib/api/applications.rb index 1c5ac2f..f541123 100644 --- a/lib/api/applications.rb +++ b/lib/api/applications.rb @@ -28,8 +28,8 @@ class W3DHub @studio_id = @data[:"studio-id"] # TODO: Do processing - @channels = @data[:channels] - @web_links = @data[:"web-links"] + @channels = @data[:channels].map { |channel| Channel.new(channel) } + @web_links = @data[:"web-links"]&.map { |link| WebLink.new(link) } || [] @extended_data = @data[:"extended-data"] color = @data[:"extended-data"].find { |h| h[:name] == "colour" }[:value].sub("#", "") @@ -38,6 +38,8 @@ class W3DHub end class Channel + attr_reader :id, :name, :user_level, :current_version + def initialize(hash) @data = hash diff --git a/lib/api/news.rb b/lib/api/news.rb new file mode 100644 index 0000000..80711b4 --- /dev/null +++ b/lib/api/news.rb @@ -0,0 +1,32 @@ +class W3DHub + class Api + class News + attr_reader :items + + def initialize(response) + @data = JSON.parse(response, symbolize_names: true) + + @items = @data[:news].map { |item| Item.new(item) } + end + + class Item + attr_reader :topic_id, :title, :blurb, :image, :uri, :author, :author_uri, :timestamp, :date, :time + + def initialize(hash) + @data = hash + + @topic_id = Integer(@data[:"topic-id"]) + @title = @data[:title] + @blurb = @data[:blurb] + @image = @data[:image].strip + @uri = @data[:uri].strip + @author = @data[:author] + @author_uri = @data[:"author-uri"].strip + @timestamp = Time.at(Integer(@data[:timestamp])) + @date = @data[:date] + @time = @data[:time] + end + end + end + end +end diff --git a/lib/pages/games.rb b/lib/pages/games.rb index 65dfff8..c1e44c0 100644 --- a/lib/pages/games.rb +++ b/lib/pages/games.rb @@ -3,7 +3,7 @@ class W3DHub class Games < Page def setup @@game_news ||= {} - @focused_game ||= W3DHub::Game.games.first + @focused_game ||= @host.applications.games.first body.clear do # Games List @@ -15,7 +15,7 @@ class W3DHub end end - populate_game_page(W3DHub::Game.games.first) + populate_game_page(@host.applications.games.first) populate_games_list end @@ -23,17 +23,17 @@ class W3DHub @games_list_container.clear do background 0xff_121920 - W3DHub::Game.games.each do |game| + @host.applications.games.each do |game| selected = game == @focused_game game_button = stack(width: 1.0, border_thickness_left: 4, border_color_left: selected ? 0xff_00acff : 0x00_000000, hover: { background: 0xff_444444 }, padding_top: 4, padding_bottom: 4) do - background game.background_color if selected + background game.color if selected flow(width: 1.0, height: 48) do stack(width: 0.3) - image game.icon, height: 48 + image "#{GAME_ROOT_PATH}/media/icons/#{game.id}.png", height: 48 end inscription game.name, width: 1.0, text_align: :center end @@ -54,27 +54,39 @@ class W3DHub @focused_game = game @game_page_container.clear do - background game.background_color + background game.color # Release channel flow(width: 1.0, height: 0.03) do # background 0xff_444411 - inscription "Release" + game.channels.each do |channel| + button "#{channel.name}", text_size: 14, padding_top: 2, padding_bottom: 2, padding_left: 4, padding_right: 4 + end end # Game Stuff flow(width: 1.0, height: 0.89) do # background 0xff_9999ff - # Gane options + # Game options stack(width: 0.25, height: 1.0, padding: 8) do # background 0xff_550055 - game.menu_items.each do |item| + # TODO: Show links for managing game install + # game.menu_items.each do |item| + # flow(width: 1.0, height: 22, margin_bottom: 8) do + # image item.image, width: 0.11 + # link item.label, text_size: 18 + # end + # end + + game.web_links.each do |item| flow(width: 1.0, height: 22, margin_bottom: 8) do - image item.image, width: 0.11 - link item.label, text_size: 18 + image EMPTY_IMAGE, width: 0.11 + link item.name, text_size: 18 do + Launchy.open(item.uri) + end end end end @@ -89,15 +101,20 @@ class W3DHub flow(width: 1.0, height: 0.08) do # background 0xff_551100 - game.play_items.each do |item| - button "#{item.label}", margin_left: 24 do - item.block&.call(game) - end - end + # TODO: Determine if game is installed or not and show apporpiante options ["Play Now" and "Single Player", "Install" and "Import"] + # game.play_items.each do |item| + # button "#{item.label}", margin_left: 24 do + # item.block&.call(game) + # end + # end + button "Install", margin_left: 24 + button "Import", margin_left: 24 + button "Play Now", margin_left: 24 + button "Single Player", margin_left: 24 end end - unless @@game_news[game.slot] + unless @@game_news[game.id] Thread.new do fetch_game_news(game) main_thread_queue << proc { populate_game_news(game) } @@ -112,42 +129,57 @@ class W3DHub end def fetch_game_news(game) - feed_uri = Excon.get( - game.news_feed, - headers: { - "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0", - "Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", - "Accept-Encoding" => "deflate", - "Accept-Language" => "en-US,en;q=0.5", - "Host" => "w3dhub.com", - "DNT" => "1" - } - ) + news = Api.news(game.id) - @@game_news[game.slot] = RSS::Parser.parse(feed_uri.body) if feed_uri.status == 200 + if news + news.items[0..9].each do |item| + # Cache Image + ext = File.basename(item.image).split(".").last + path = "#{CACHE_PATH}/#{Digest::SHA2.hexdigest(item.image)}.#{ext}" + + next if File.exist?(path) + + response = Excon.get(item.image) + + if response.status == 200 + File.open(path, "wb") do |f| + f.write(response.body) + end + end + end + + @@game_news[game.id] = news + end end def populate_game_news(game) return unless @focused_game == game - if (feed = @@game_news[game.slot]) + if (feed = @@game_news[game.id]) @game_news_container.clear do - feed.items.sort_by { |i| i.pubDate }.reverse[0..9].each do |item| + feed.items.sort_by { |i| i.timestamp }.reverse[0..9].each do |item| flow(width: 0.5, height: 128, margin: 4) do # background 0x88_000000 - image game.icon, width: 0.4, padding: 4 + ext = File.basename(item.image).split(".").last + path = "#{CACHE_PATH}/#{Digest::SHA2.hexdigest(item.image)}.#{ext}" + + if File.exist?(path) + image path, width: 0.4, padding: 4 + else + image BLACK_IMAGE, width: 0.4, padding: 4 + end stack(width: 0.6, height: 1.0) do stack(width: 1.0, height: 112) do para "#{item.title}" - inscription "#{Sanitize.fragment(item.description[0...180]).strip}" + inscription "#{item.blurb.strip[0..180]}" end flow(width: 1.0) do - inscription item.pubDate.strftime("%Y-%m-%d"), width: 0.5 + inscription item.timestamp.strftime("%Y-%m-%d"), width: 0.5 link "Read More", width: 0.5, text_align: :right, text_size: 14 do - Launchy.open(item.link) + Launchy.open(item.uri) end end end diff --git a/lib/states/boot.rb b/lib/states/boot.rb index 408e626..8342342 100644 --- a/lib/states/boot.rb +++ b/lib/states/boot.rb @@ -50,28 +50,30 @@ class W3DHub ) end - send(:"#{@tasks.keys[@task_index]}") if @tasks.dig(@tasks.keys[@task_index], :complete) == false + if @tasks.dig(@tasks.keys[@task_index], :started) == false + p @tasks.keys[@task_index] + @tasks[@tasks.keys[@task_index]][:started] = true + + send(:"#{@tasks.keys[@task_index]}") + end @task_index += 1 if @tasks.dig(@tasks.keys[@task_index], :complete) end def refresh_user_token - @tasks[:refresh_user_token][:started] = true @tasks[:refresh_user_token][:complete] = true @refresh_token = nil end def service_status - @tasks[:service_status][:started] = true - Thread.new do @service_status = Api.service_status - if service_status - if !service_status.authentication? || !service_status.package_download? + if @service_status + if !@service_status.authentication? || !@service_status.package_download? # FIXME: MAIN THREAD! - @status_label.value = "Authentication is #{service_status.authentication? ? 'Okay' : 'Down'}. Package Download is #{service_status.package_download? ? 'Okay' : 'Down'}." + @status_label.value = "Authentication is #{@service_status.authentication? ? 'Okay' : 'Down'}. Package Download is #{@service_status.package_download? ? 'Okay' : 'Down'}." end @tasks[:service_status][:complete] = true @@ -85,19 +87,13 @@ class W3DHub def applications @status_label.value = "Checking for updates..." - warn "ALREADY STARTED APPLICATIONS!!!" if @tasks[:applications][:started] - - return if @tasks[:applications][:started] - - @tasks[:applications][:started] = true - Thread.new do @applications = Api.applications - if applications - pp applications.games.first - + if @applications @tasks[:applications][:complete] = true + else + # FIXME: Failed to retreive! end end end diff --git a/lib/states/interface.rb b/lib/states/interface.rb index 04da09e..9625e33 100644 --- a/lib/states/interface.rb +++ b/lib/states/interface.rb @@ -92,6 +92,7 @@ class W3DHub button( get_image("#{GAME_ROOT_PATH}/media/ui_icons/import.png"), + enabled: false, tip: "Download Manager", image_height: 1.0, padding_left: 4, diff --git a/w3dhub.rb b/w3dhub.rb index 0d9ba0f..7416943 100644 --- a/w3dhub.rb +++ b/w3dhub.rb @@ -1,12 +1,14 @@ require "cyberarm_engine" -require "sanitize" -require "rss" +require "digest" require "zlib" require "launchy" -GAME_ROOT_PATH = File.expand_path(".", __dir__) -EMPTY_IMAGE = Gosu::Image.from_blob(1, 1) -BLACK_IMAGE = Gosu::Image.from_blob(1, 1, "\x00\x00\x00\xff") +class W3DHub + GAME_ROOT_PATH = File.expand_path(".", __dir__) + CACHE_PATH = "#{GAME_ROOT_PATH}/data/cache" + EMPTY_IMAGE = Gosu::Image.from_blob(1, 1) + BLACK_IMAGE = Gosu::Image.from_blob(1, 1, "\x00\x00\x00\xff") +end require_relative "lib/version" require_relative "lib/window" @@ -16,13 +18,15 @@ require_relative "lib/states/interface" require_relative "lib/api" require_relative "lib/api/service_status" require_relative "lib/api/applications" +require_relative "lib/api/news" -require_relative "lib/game" -require_relative "lib/games/renegade" -require_relative "lib/games/expansive_civilian_warfare" -require_relative "lib/games/interim_apex" -require_relative "lib/games/ra_a_path_beyond" -require_relative "lib/games/ts_reborn" +# require_relative "lib/game" +# require_relative "lib/games/renegade" +# require_relative "lib/games/expansive_civilian_warfare" +# require_relative "lib/games/interim_apex" +# require_relative "lib/games/ra_a_path_beyond" +# require_relative "lib/games/ts_reborn" +# W3DHub::Game.load_games require_relative "lib/page" require_relative "lib/pages/games" @@ -35,6 +39,4 @@ require_relative "lib/pages/download_manager" require_relative "lib/renegade_server" require_relative "lib/renegade_player" -W3DHub::Game.load_games - W3DHub::Window.new(width: 980, height: 720, borderless: false).show