Compare commits

...

4 Commits

Author SHA1 Message Date
4997cfabb0 Fixed not handling filename case for patches 2025-08-26 09:23:54 -05:00
The Unnamed Engineer
0c906464f0 case desensitize unzip 2025-08-26 08:55:27 -05:00
The Unnamed Engineer
5bafc77d97 Update task.rb
Modify all potentially case sensitive file operations to operate in a case-insensitive manner.
2025-08-26 08:55:27 -05:00
30aa44312d Fixed failing to download application manifests unless logged in by checking which source the application/channel orginated from, updated gems. 2025-08-26 08:51:08 -05:00
4 changed files with 48 additions and 28 deletions

View File

@@ -8,7 +8,7 @@ GEM
digest-crc (0.7.0) digest-crc (0.7.0)
rake (>= 12.0.0, < 14.0.0) rake (>= 12.0.0, < 14.0.0)
event_emitter (0.2.6) event_emitter (0.2.6)
excon (1.2.7) excon (1.3.0)
logger logger
ffi (1.17.2-x64-mingw-ucrt) ffi (1.17.2-x64-mingw-ucrt)
ffi (1.17.2-x86_64-linux-gnu) ffi (1.17.2-x86_64-linux-gnu)
@@ -22,8 +22,8 @@ GEM
logger (1.7.0) logger (1.7.0)
mutex_m (0.3.0) mutex_m (0.3.0)
rake (13.3.0) rake (13.3.0)
rexml (3.4.1) rexml (3.4.2)
rubyzip (2.4.1) rubyzip (3.0.2)
sdl2-bindings (0.2.3) sdl2-bindings (0.2.3)
ffi (~> 1.15) ffi (~> 1.15)
websocket (1.2.11) websocket (1.2.11)
@@ -58,4 +58,4 @@ DEPENDENCIES
win32-security win32-security
BUNDLED WITH BUNDLED WITH
2.6.7 2.6.8

View File

@@ -240,7 +240,7 @@ class W3DHub
response = post("/apis/launcher/1/get-applications", DEFAULT_HEADERS, nil, backend) response = post("/apis/launcher/1/get-applications", DEFAULT_HEADERS, nil, backend)
if response.status == 200 if response.status == 200
Applications.new(response.body) Applications.new(response.body, backend)
else else
logger.error(LOG_TAG) { "Failed to fetch applications list:" } logger.error(LOG_TAG) { "Failed to fetch applications list:" }
logger.error(LOG_TAG) { response } logger.error(LOG_TAG) { response }
@@ -294,7 +294,7 @@ class W3DHub
next next
end end
# If the access levels doen't match then overwrite alternate's channel with primary's channel # If the access levels don't match then overwrite alternate's channel with primary's channel
if channel.user_level != _channel.user_level if channel.user_level != _channel.user_level
# Replace alternate's channel with primary's channel # Replace alternate's channel with primary's channel
_game.channels[_game.channels.index(_channel)] = channel _game.channels[_game.channels.index(_channel)] = channel
@@ -303,7 +303,7 @@ class W3DHub
next next
end end
# If versions doen't match then pick whichever one is higher # If versions don't match then pick whichever one is higher
if Gem::Version.new(channel.current_version) > Gem::Version.new(_channel.current_version) if Gem::Version.new(channel.current_version) > Gem::Version.new(_channel.current_version)
# Replace alternate's channel with primary's channel # Replace alternate's channel with primary's channel
_game.channels[_game.channels.index(_channel)] = channel _game.channels[_game.channels.index(_channel)] = channel

View File

@@ -3,14 +3,14 @@ class W3DHub
class Applications class Applications
attr_reader :data attr_reader :data
def initialize(response) def initialize(response, source = nil)
@data = JSON.parse(response, symbolize_names: true) @data = JSON.parse(response, symbolize_names: true)
games = @data[:applications].select { |a| a[:category] == "games" } games = @data[:applications].select { |a| a[:category] == "games" }
@games = [] @games = []
games.each { |hash| @games << Game.new(hash) } games.each { |hash| @games << Game.new(hash, source) }
@games.sort_by!(&:name).reverse @games.sort_by!(&:name).reverse
end end
@@ -20,9 +20,11 @@ class W3DHub
class Game class Game
attr_reader :id, :name, :type, :category, :studio_id, :channels, :web_links, :color attr_reader :id, :name, :type, :category, :studio_id, :channels, :web_links, :color
attr_reader :___source
def initialize(hash) def initialize(hash, source = nil)
@data = hash @data = hash
@data[:___source] = source if source
@id = @data[:id].to_s @id = @data[:id].to_s
@name = @data[:name] @name = @data[:name]
@@ -31,7 +33,7 @@ class W3DHub
@studio_id = @data[:"studio-id"] @studio_id = @data[:"studio-id"]
# TODO: Do processing # TODO: Do processing
@channels = @data[:channels].map { |channel| Channel.new(channel) } @channels = @data[:channels].map { |channel| Channel.new(channel, source) }
@web_links = @data[:"web-links"]&.map { |link| WebLink.new(link) } || [] @web_links = @data[:"web-links"]&.map { |link| WebLink.new(link) } || []
@extended_data = @data[:"extended-data"] @extended_data = @data[:"extended-data"]
@@ -55,17 +57,34 @@ class W3DHub
@uses_ren_folder @uses_ren_folder
end end
def source
@data[:___source]&.to_sym || :w3dhub
end
def source=(sym)
@data[:___source] = sym
end
class Channel class Channel
attr_reader :id, :name, :user_level, :current_version attr_reader :id, :name, :user_level, :current_version
def initialize(hash) def initialize(hash, source = nil)
@data = hash @data = hash
@data[:___source] = source
@id = @data[:id].to_s @id = @data[:id].to_s
@name = @data[:name] @name = @data[:name]
@user_level = @data[:"user-level"] @user_level = @data[:"user-level"]
@current_version = @data[:"current-version"] @current_version = @data[:"current-version"]
end end
def source
@data[:___source]&.to_sym || :w3dhub
end
def source=(sym)
@data[:___source] = sym
end
end end
class WebLink class WebLink

View File

@@ -112,6 +112,11 @@ class W3DHub
@task_state == :failed @task_state == :failed
end end
# Helper method to normalize file paths for case-insensitive comparison
def normalize_path(path)
path.to_s.gsub("\\", "/").downcase
end
def failure_reason def failure_reason
@task_failure_reason || "" @task_failure_reason || ""
end end
@@ -259,7 +264,7 @@ class W3DHub
next if packages.detect do |pkg| next if packages.detect do |pkg|
pkg.category == "games" && pkg.category == "games" &&
pkg.subcategory == @app_id && pkg.subcategory == @app_id &&
pkg.name == file.package && pkg.name.to_s.casecmp?(file.package.to_s) &&
pkg.version == file.version pkg.version == file.version
end end
@@ -295,10 +300,8 @@ class W3DHub
@files.reverse.each do |file| @files.reverse.each do |file|
break unless folder_exists break unless folder_exists
safe_file_name = file.name.gsub("\\", "/") # Normalize file paths to handle case-insensitive comparisons
# Fix borked Data -> data 'cause Windows don't care about capitalization safe_file_name = normalize_path(file.name)
safe_file_name.sub!("Data/", "data/")
file_path = "#{path}/#{safe_file_name}" file_path = "#{path}/#{safe_file_name}"
processed_files += 1 processed_files += 1
@@ -369,7 +372,7 @@ class W3DHub
} }
end end
package_details = Api.package_details(hashes) package_details = Api.package_details(hashes, @channel.source || :w3dhub)
unless package_details unless package_details
fail!("Failed to fetch package details") fail!("Failed to fetch package details")
@@ -383,9 +386,9 @@ class W3DHub
end end
package = @packages.find do |pkg| package = @packages.find do |pkg|
pkg.category == rich.category && pkg.category.to_s.casecmp?(rich.category.to_s) &&
pkg.subcategory == rich.subcategory && pkg.subcategory.to_s.casecmp?(rich.subcategory.to_s) &&
"#{pkg.name}.zip" == rich.name && "#{pkg.name}.zip".casecmp?(rich.name) &&
pkg.version == rich.version pkg.version == rich.version
end end
@@ -596,7 +599,7 @@ class W3DHub
# Check for and integrity of local manifest # Check for and integrity of local manifest
package = nil package = nil
array = Api.package_details([{ category: category, subcategory: subcategory, name: name, version: version }]) array = Api.package_details([{ category: category, subcategory: subcategory, name: name, version: version }], @channel.source || :w3dhub)
if array.is_a?(Array) if array.is_a?(Array)
package = array.first package = array.first
else else
@@ -707,8 +710,8 @@ class W3DHub
logger.info(LOG_TAG) { " Unpacking patch \"#{package_path}\" in \"#{temp_path}\"" } logger.info(LOG_TAG) { " Unpacking patch \"#{package_path}\" in \"#{temp_path}\"" }
unzip(package_path, temp_path) unzip(package_path, temp_path)
# Fix borked Data -> data 'cause Windows don't care about capitalization # Normalize the path to handle case-insensitivity consistently
safe_file_name = "#{manifest_file.name.sub('Data/', 'data/')}" safe_file_name = normalize_path(manifest_file.name)
logger.info(LOG_TAG) { " Loading #{temp_path}/#{safe_file_name}.patch..." } logger.info(LOG_TAG) { " Loading #{temp_path}/#{safe_file_name}.patch..." }
patch_mix = W3DHub::Mixer::Reader.new(file_path: "#{temp_path}/#{safe_file_name}.patch", ignore_crc_mismatches: false) patch_mix = W3DHub::Mixer::Reader.new(file_path: "#{temp_path}/#{safe_file_name}.patch", ignore_crc_mismatches: false)
@@ -749,10 +752,8 @@ class W3DHub
stream = Zip::InputStream.new(File.open(package_path)) stream = Zip::InputStream.new(File.open(package_path))
while (entry = stream.get_next_entry) while (entry = stream.get_next_entry)
# Normalize the path to handle case-insensitivity consistently
safe_file_name = entry.name.gsub("\\", "/") safe_file_name = normalize_path(entry.name)
# Fix borked Data -> data 'cause Windows don't care about capitalization
safe_file_name.sub!("Data/", "data/")
dir_path = "#{path}/#{File.dirname(safe_file_name)}" dir_path = "#{path}/#{File.dirname(safe_file_name)}"
unless dir_path.end_with?("/.") || Dir.exist?(dir_path) unless dir_path.end_with?("/.") || Dir.exist?(dir_path)