diff --git a/Lauhdutin/@Resources/Backend/Enums.py b/Lauhdutin/@Resources/Backend/Enums.py index f6a1f46..f225a95 100644 --- a/Lauhdutin/@Resources/Backend/Enums.py +++ b/Lauhdutin/@Resources/Backend/Enums.py @@ -3,9 +3,11 @@ class GameKeys(): BANNER_ERROR = "bannererror" BANNER_PATH = "banner" BANNER_URL = "bannerurl" + ERROR = "error" HIDDEN = "hidden" HOURS_LAST_TWO_WEEKS = "hourslast2weeks" HOURS_TOTAL = "hourstotal" + INVALID_PATH = "invalidpatherror" LASTPLAYED = "lastplayed" NAME = "title" NOT_INSTALLED = "notinstalled" diff --git a/Lauhdutin/@Resources/Backend/Steam.py b/Lauhdutin/@Resources/Backend/Steam.py index 939f291..6c7ea65 100644 --- a/Lauhdutin/@Resources/Backend/Steam.py +++ b/Lauhdutin/@Resources/Backend/Steam.py @@ -365,6 +365,9 @@ def get_shortcuts(self): game[GameKeys.BANNER_PATH] = "Steam shortcuts\\%s.jpg" % ( game[GameKeys.NAME]) game[GameKeys.PATH], shortcut = self.parse_shortcut_path(shortcut) + if not os.path.isfile(game[GameKeys.PATH]): + game[GameKeys.ERROR] = True + game[GameKeys.INVALID_PATH] = True game[GameKeys.PATH] = "steam://rungameid/%s" % ( self.parse_shortcut_app_id(game[GameKeys.PATH], game[GameKeys.NAME])) diff --git a/Lauhdutin/@Resources/Backend/WindowsShortcuts.py b/Lauhdutin/@Resources/Backend/WindowsShortcuts.py index 9bf3d35..42f74ac 100644 --- a/Lauhdutin/@Resources/Backend/WindowsShortcuts.py +++ b/Lauhdutin/@Resources/Backend/WindowsShortcuts.py @@ -48,12 +48,9 @@ def process_shortcut(self, a_shortcut):# a_name, a_path): return (None, None) game_dict = {} game_dict[GameKeys.NAME] = name - #if not os.path.isfile(target_path): - # TODO - # - Add a field to the dictionary, if target_path is no longer valid - # - Create an overlay for Windows shortcuts that are no longer valid - # - Implement overlay in GUI.lua - # - Update test once implemented + if not os.path.isfile(target_path): + game_dict[GameKeys.ERROR] = True + game_dict[GameKeys.INVALID_PATH] = True game_dict[GameKeys.PATH] = target_path game_dict[GameKeys.LASTPLAYED] = 0 game_dict[GameKeys.PLATFORM] = Platform.WINDOWS_SHORTCUT diff --git a/Lauhdutin/@Resources/Frontend/GUI.lua b/Lauhdutin/@Resources/Frontend/GUI.lua index f1d3f1f..c262d79 100644 --- a/Lauhdutin/@Resources/Frontend/GUI.lua +++ b/Lauhdutin/@Resources/Frontend/GUI.lua @@ -27,9 +27,11 @@ function Initialize() BANNER_ERROR = "bannererror", BANNER_PATH = "banner", BANNER_URL = "bannerurl", + ERROR = "error", HIDDEN = "hidden", HOURS_LAST_TWO_WEEKS = "hourslast2weeks", HOURS_TOTAL = "hourstotal", + INVALID_PATH = "invalidpatherror", LASTPLAYED = "lastplayed", NAME = "title", NOT_INSTALLED = "notinstalled", @@ -366,45 +368,67 @@ end if T_FILTERED_GAMES ~= nil then local nSlotCount = tonumber(T_SETTINGS[S_SETTING_SLOT_COUNT]) local j = N_SCROLL_INDEX - for i = 1, nSlotCount do - if j > 0 and j <= #T_FILTERED_GAMES then + for i = 1, nSlotCount do -- Iterate through each slot. + if j > 0 and j <= #T_FILTERED_GAMES then -- If the scroll index, 'j', is a valid index in the table 'T_FILTERED_GAMES' SKIN:Bang('[!SetVariable SlotPath' .. i .. ' "' .. tostring(j) .. '"][!SetVariable SlotName' .. i .. ' "' .. T_FILTERED_GAMES[j][GAME_KEYS.NAME] .. '"]') if BannerExists(T_FILTERED_GAMES[j][GAME_KEYS.BANNER_PATH]) then SKIN:Bang('!SetVariable SlotImage' .. i .. ' "#@#Banners\\' .. T_FILTERED_GAMES[j][GAME_KEYS.BANNER_PATH] .. '"') else SKIN:Bang('!SetVariable SlotImage' .. i .. ' ""') end - if N_LAUNCH_STATE == T_LAUNCH_STATES.LAUNCH then - if T_SETTINGS['show_hours_played'] and T_FILTERED_GAMES[j][GAME_KEYS.HOURS_TOTAL] then - local totalHoursPlayed = T_FILTERED_GAMES[j][GAME_KEYS.HOURS_TOTAL] - local hoursPlayed = math.floor(totalHoursPlayed) - local minutesPlayed = math.floor((totalHoursPlayed - hoursPlayed) * 60) - if T_FILTERED_GAMES[j][GAME_KEYS.NOT_INSTALLED] == true then - SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Install via ' .. PLATFORM_DESCRIPTION[T_FILTERED_GAMES[j][GAME_KEYS.PLATFORM]+1] .. '#CRLF##CRLF##CRLF##CRLF##CRLF#' .. hoursPlayed .. ' hours ' .. minutesPlayed .. ' minutes played"]')--[!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightInstall.png"]') + if T_SETTINGS['slot_highlight'] then + if N_LAUNCH_STATE == T_LAUNCH_STATES.LAUNCH then + if T_SETTINGS['show_hours_played'] and T_FILTERED_GAMES[j][GAME_KEYS.HOURS_TOTAL] then + local totalHoursPlayed = T_FILTERED_GAMES[j][GAME_KEYS.HOURS_TOTAL] + local hoursPlayed = math.floor(totalHoursPlayed) + local minutesPlayed = math.floor((totalHoursPlayed - hoursPlayed) * 60) + if T_FILTERED_GAMES[j][GAME_KEYS.NOT_INSTALLED] == true then + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Install via ' .. PLATFORM_DESCRIPTION[T_FILTERED_GAMES[j][GAME_KEYS.PLATFORM]+1] .. '#CRLF##CRLF##CRLF##CRLF##CRLF#' .. hoursPlayed .. ' hours ' .. minutesPlayed .. ' minutes played"]') + elseif T_FILTERED_GAMES[j][GAME_KEYS.INVALID_PATH] == true then + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Invalid path#CRLF##CRLF##CRLF##CRLF##CRLF#' .. hoursPlayed .. ' hours ' .. minutesPlayed .. ' minutes played"]') + else + if T_SETTINGS["show_platform"] then + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "' .. PLATFORM_DESCRIPTION[T_FILTERED_GAMES[j][GAME_KEYS.PLATFORM]+1] .. '#CRLF##CRLF##CRLF##CRLF##CRLF#' .. hoursPlayed .. ' hours ' .. minutesPlayed .. ' minutes played"]') + else + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "#CRLF##CRLF##CRLF##CRLF##CRLF#' .. hoursPlayed .. ' hours ' .. minutesPlayed .. ' minutes played"]') + end + end else - SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "' .. PLATFORM_DESCRIPTION[T_FILTERED_GAMES[j][GAME_KEYS.PLATFORM]+1] .. '#CRLF##CRLF##CRLF##CRLF##CRLF#' .. hoursPlayed .. ' hours ' .. minutesPlayed .. ' minutes played"]')--[!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightPlay.png"]') + if T_FILTERED_GAMES[j][GAME_KEYS.NOT_INSTALLED] == true then + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Install via ' .. PLATFORM_DESCRIPTION[T_FILTERED_GAMES[j][GAME_KEYS.PLATFORM]+1] .. '#CRLF##CRLF##CRLF##CRLF##CRLF#"]') + elseif T_FILTERED_GAMES[j][GAME_KEYS.INVALID_PATH] == true then + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Invalid path#CRLF##CRLF##CRLF##CRLF##CRLF#"]') + else + if T_SETTINGS["show_platform"] then + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "' .. PLATFORM_DESCRIPTION[T_FILTERED_GAMES[j][GAME_KEYS.PLATFORM]+1] .. '#CRLF##CRLF##CRLF##CRLF##CRLF#"]') + else + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" ""]') + end + end end - else if T_FILTERED_GAMES[j][GAME_KEYS.NOT_INSTALLED] == true then - SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Install via ' .. PLATFORM_DESCRIPTION[T_FILTERED_GAMES[j][GAME_KEYS.PLATFORM]+1] .. '#CRLF##CRLF##CRLF##CRLF##CRLF#"]')--[!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightInstall.png"]') + SKIN:Bang('[!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightInstall.png"]') + elseif T_FILTERED_GAMES[j][GAME_KEYS.ERROR] == true then + SKIN:Bang('[!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightError.png"]') else - SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "' .. PLATFORM_DESCRIPTION[T_FILTERED_GAMES[j][GAME_KEYS.PLATFORM]+1] .. '#CRLF##CRLF##CRLF##CRLF##CRLF#"]')--[!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightPlay.png"]') + SKIN:Bang('[!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightPlay.png"]') end + elseif N_LAUNCH_STATE == T_LAUNCH_STATES.HIDE then + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Hide"][!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightHide.png"]') + elseif N_LAUNCH_STATE == T_LAUNCH_STATES.UNHIDE then + SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Unhide"][!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightUnhide.png"]') end - if T_FILTERED_GAMES[j][GAME_KEYS.NOT_INSTALLED] == true then - SKIN:Bang('[!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightInstall.png"]') - else - SKIN:Bang('[!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightPlay.png"]') - end - elseif N_LAUNCH_STATE == T_LAUNCH_STATES.HIDE then - SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Hide"][!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightHide.png"]') - elseif N_LAUNCH_STATE == T_LAUNCH_STATES.UNHIDE then - SKIN:Bang('[!SetVariable "SlotHighlightMessage' .. i .. '" "Unhide"][!SetOption "SlotHighlight' .. i .. '" "ImageName" "#@#Icons\\SlotHighlightUnhide.png"]') end - else - SKIN:Bang('[!SetVariable SlotPath' .. i .. ' ""][!SetVariable SlotImage' .. i .. ' ""][!SetVariable SlotName' .. i .. ' ""][!SetVariable "SlotHighlightMessage' .. i .. '" ""]') + else -- Slot has no game to show. + if T_SETTINGS['slot_highlight'] then + SKIN:Bang('[!SetVariable SlotPath' .. i .. ' ""][!SetVariable SlotImage' .. i .. ' ""][!SetVariable SlotName' .. i .. ' ""][!SetVariable "SlotHighlightMessage' .. i .. '" ""]') + else + SKIN:Bang('[!SetVariable SlotPath' .. i .. ' ""][!SetVariable SlotImage' .. i .. ' ""][!SetVariable SlotName' .. i .. ' ""]') + end + end + if T_SETTINGS['slot_highlight'] then + SKIN:Bang('[!UpdateMeterGroup "SlotHighlight' .. i .. '"]') end - SKIN:Bang('[!UpdateMeterGroup "SlotHighlight' .. i .. '"]') j = j + 1 end end @@ -443,6 +467,7 @@ end local sPath = tGame[GAME_KEYS.PATH] if sPath ~= nil then tGame[GAME_KEYS.LASTPLAYED] = os.time() + bNotInstalled = tGame[GAME_KEYS.NOT_INSTALLED] if tGame[GAME_KEYS.HIDDEN] == true then tGame[GAME_KEYS.HIDDEN] = nil for i = 1, #T_HIDDEN_GAMES do -- Move game from T_HIDDEN_GAMES to T_ALL_GAMES @@ -454,7 +479,7 @@ end if tGame[GAME_KEYS.NOT_INSTALLED] == true then tGame[GAME_KEYS.NOT_INSTALLED] = nil end - elseif tGame[GAME_KEYS.NOT_INSTALLED] == true then + elseif bNotInstalled == true then tGame[GAME_KEYS.NOT_INSTALLED] = nil for i = 1, #T_NOT_INSTALLED_GAMES do -- Move game from T_NOT_INSTALLED_GAMES to T_ALL_GAMES if T_NOT_INSTALLED_GAMES[i] == tGame then @@ -467,15 +492,24 @@ end FilterBy('') Sort() PopulateSlots() - T_RECENTLY_LAUNCHED_GAME = tGame - if StartsWith(sPath, 'steam://') then - SKIN:Bang('[!SetOption "ProcessMonitor" "ProcessName" "GameOverlayUI.exe"]') - else - local processPath = string.gsub(string.gsub(sPath, "\\", "/"), "//", "/") - local processName = processPath:reverse():match("(exe%p[^\\/:%*?<>|]+)/"):reverse() - SKIN:Bang('[!SetOption "ProcessMonitor" "ProcessName" "' .. processName .. '"]') + if tGame[GAME_KEYS.ERROR] == true then + SKIN:Bang('[!Log "Error: There is something wrong with ' .. tGame[GAME_KEYS.NAME] .. '"]') + return + end + if bNotInstalled ~= true then + T_RECENTLY_LAUNCHED_GAME = tGame + if StartsWith(sPath, 'steam://') then + SKIN:Bang('[!SetOption "ProcessMonitor" "ProcessName" "GameOverlayUI.exe"]') + else + local processPath = string.gsub(string.gsub(sPath, "\\", "/"), "//", "/") + local processName = processPath:reverse():match("(exe%p[^\\/:%*?<>|]+)/"):reverse() + SKIN:Bang('[!SetOption "ProcessMonitor" "ProcessName" "' .. processName .. '"]') + end + SKIN:Bang('[!UpdateMeasure "ProcessMonitor"]') + if T_SETTINGS['start_game_bang'] ~= nil and T_SETTINGS['start_game_bang'] ~= '' then + SKIN:Bang((T_SETTINGS['start_game_bang']:gsub('`', '"'))) + end end - SKIN:Bang('[!UpdateMeasure "ProcessMonitor"]') SKIN:Bang('["' .. sPath .. '"]') end elseif N_LAUNCH_STATE == T_LAUNCH_STATES.HIDE then @@ -569,6 +603,9 @@ end T_RECENTLY_LAUNCHED_GAME[GAME_KEYS.HOURS_TOTAL] = hoursPlayed + T_RECENTLY_LAUNCHED_GAME[GAME_KEYS.HOURS_TOTAL] WriteGames() PopulateSlots() + if T_SETTINGS['stop_game_bang'] ~= nil and T_SETTINGS['stop_game_bang'] ~= '' then + SKIN:Bang((T_SETTINGS['stop_game_bang']:gsub('`', '"'))) + end end end diff --git a/Lauhdutin/@Resources/Frontend/Settings.lua b/Lauhdutin/@Resources/Frontend/Settings.lua index 83046af..9f5382f 100644 --- a/Lauhdutin/@Resources/Frontend/Settings.lua +++ b/Lauhdutin/@Resources/Frontend/Settings.lua @@ -29,6 +29,9 @@ function Initialize() if SETTINGS['show_hours_played'] == nil then SETTINGS['show_hours_played'] = true end + if SETTINGS['show_platform'] == nil then + SETTINGS['show_platform'] = true + end if SETTINGS['steam_path'] == nil then SETTINGS['steam_path'] = "" end @@ -41,6 +44,12 @@ function Initialize() if SETTINGS['steam_id64'] == nil then SETTINGS['steam_id64'] = "" end + if SETTINGS['start_game_bang'] == nil then + SETTINGS['start_game_bang'] = "" + end + if SETTINGS['stop_game_bang'] == nil then + SETTINGS['stop_game_bang'] = "" + end if SETTINGS['sortstate'] == nil then SETTINGS['sortstate'] = "0" end @@ -133,6 +142,10 @@ function UpdateSettings() SKIN:Bang('[!SetOption "GalaxyPathInput" "DefaultValue" "' .. SETTINGS['galaxy_path'] ..'"]') SKIN:Bang('[!SetOption "PythonPathStatus" "Text" "' .. tostring(SETTINGS['python_path']) .. '"]') SKIN:Bang('[!SetOption "PythonPathInput" "DefaultValue" "' .. SETTINGS['python_path'] ..'"]') + SKIN:Bang('[!SetOption "StartGameBangStatus" "Text" "' .. tostring(SETTINGS['start_game_bang']) .. '"]') + SKIN:Bang('[!SetOption "StartGameBangInput" "DefaultValue" "' .. SETTINGS['start_game_bang'] ..'"]') + SKIN:Bang('[!SetOption "StopGameBangStatus" "Text" "' .. tostring(SETTINGS['stop_game_bang']) .. '"]') + SKIN:Bang('[!SetOption "StopGameBangInput" "DefaultValue" "' .. SETTINGS['stop_game_bang'] ..'"]') if SETTINGS['orientation'] == 'vertical' then SKIN:Bang('[!SetOption "SkinOrientationStatus" "Text" "Vertical"]') else @@ -148,6 +161,11 @@ function UpdateSettings() else SKIN:Bang('[!SetOption "ShowHoursPlayedStatus" "Text" "Disabled"]') end + if SETTINGS['show_platform'] == true then + SKIN:Bang('[!SetOption "ShowPlatformStatus" "Text" "Enabled"]') + else + SKIN:Bang('[!SetOption "ShowPlatformStatus" "Text" "Disabled"]') + end SKIN:Bang('[!Update]') SKIN:Bang('[!Redraw]') end @@ -311,6 +329,16 @@ function AcceptPythonPath(aPath) UpdateSettings() end +function AcceptStartGameBang(aPath) + SETTINGS['start_game_bang'] = aPath + UpdateSettings() +end + +function AcceptStopGameBang(aPath) + SETTINGS['stop_game_bang'] = aPath + UpdateSettings() +end + function ToggleOrientation() if SETTINGS['orientation'] == 'vertical' then SETTINGS['orientation'] = 'horizontal' @@ -338,6 +366,15 @@ function ToggleShowHoursPlayed() UpdateSettings() end +function ToggleShowPlatform() + if SETTINGS['show_platform'] == true then + SETTINGS['show_platform'] = false + else + SETTINGS['show_platform'] = true + end + UpdateSettings() +end + function ReadJSON(asPath) local f = io.open(asPath, 'r') if f ~= nil then diff --git a/Lauhdutin/@Resources/Icons/SlotHighlightError.png b/Lauhdutin/@Resources/Icons/SlotHighlightError.png new file mode 100644 index 0000000..230edc6 Binary files /dev/null and b/Lauhdutin/@Resources/Icons/SlotHighlightError.png differ diff --git a/Lauhdutin/Main.ini b/Lauhdutin/Main.ini index a44c3a4..82fb25d 100644 --- a/Lauhdutin/Main.ini +++ b/Lauhdutin/Main.ini @@ -2,7 +2,7 @@ Name=Lauhdutin Author=Kapiainen Information=A Rainmeter skin for launching games. -Version=2.2.0 +Version=2.3.0 License=MIT [Rainmeter] diff --git a/Lauhdutin/Settings.ini b/Lauhdutin/Settings.ini index 46e781a..5e62d72 100644 --- a/Lauhdutin/Settings.ini +++ b/Lauhdutin/Settings.ini @@ -2,7 +2,7 @@ Name=Lauhdutin settings Author=Kapiainen Information=A Rainmeter skin for launching games. -Version=2.2.0 +Version=2.3.0 License=MIT [Rainmeter] @@ -58,7 +58,7 @@ X=((#WindowWidth# / 4) - 1) Y=(#TabHeight# / 2) W=((#WindowWidth# / 2) - 1) H=#TabHeight# -Text=Frontend +Text=Appearance FontFace=Arial FontSize=(#TabHeight#/3) FontColor=#ButtonTextColor# @@ -84,7 +84,7 @@ X=(#WindowWidth# - (#WindowWidth# / 4) + 1) Y=(#TabHeight# / 2) W=((#WindowWidth# / 2) - 1) H=#TabHeight# -Text=Backend +Text=Functionality FontFace=Arial FontSize=(#TabHeight#/3) FontColor=#ButtonTextColor# @@ -265,7 +265,7 @@ FontColor=255,255,255,255 FontFace=Arial StringAlign=Right FontSize=(#TabHeight#/3) -X=(#IncrementButtonDimension# + #WindowWidth# / 4) +X=(#IncrementButtonDimension# / 2 + #WindowWidth# / 4) Y=(#TabHeight# + 10) W=(#WindowWidth# / 8) H=#IncrementButtonDimension# @@ -311,7 +311,7 @@ FontFace=Arial StringAlign=Right ;Seqoe UI FontSize=(#TabHeight#/3) -X=(#IncrementButtonDimension# + #WindowWidth# / 4) +X=(#IncrementButtonDimension# / 2 + #WindowWidth# / 4) Y=(2 * #TabHeight# + 10) W=(#WindowWidth# / 8) H=#IncrementButtonDimension# @@ -357,7 +357,7 @@ FontFace=Arial StringAlign=Right ;Seqoe UI FontSize=(#TabHeight#/3) -X=(#IncrementButtonDimension# + #WindowWidth# / 4) +X=(#IncrementButtonDimension# / 2 + #WindowWidth# / 4) Y=(3 * #TabHeight# + 10) W=(#WindowWidth# / 8) H=#IncrementButtonDimension# @@ -447,7 +447,7 @@ MeterStyle=LayoutOptionTitleTemplate Y=(6 * #TabHeight# + 10 + (#IncrementButtonDimension# / 2)) Text=Hours played ToolTipTitle=Hours played -ToolTipText=Show the total number of hours played when highlighting a slot. Requires highlighting to be enabled. Only supports Steam games at the moment. +ToolTipText=Show the total number of hours played when highlighting a slot. Requires highlighting to be enabled. [ShowHoursPlayedButton] Meter=Image @@ -477,6 +477,43 @@ AntiAlias=1 DynamicVariables=1 Group=Layout +;------------------------ Platform ------------------------ +[ShowPlatformTitle] +Meter=String +MeterStyle=LayoutOptionTitleTemplate +Y=(7 * #TabHeight# + 10 + (#IncrementButtonDimension# / 2)) +Text=Platform +ToolTipTitle=Platform +ToolTipText=Show the platform that the game originates from when highlighting a slot. Requires highlighting to be enabled. + +[ShowPlatformButton] +Meter=Image +X=(#WindowWidth# / 4)r +Y=(-#IncrementButtonDimension# / 2)r +W=(#WindowWidth# / 8 + 5 * #IncrementButtonDimension# / 2) +H=#IncrementButtonDimension# +SolidColor=#ButtonColor# +DynamicVariables=1 +LeftMouseDownAction=[!CommandMeasure "SettingsScript" "ToggleShowPlatform()"] +Group=Layout + +[ShowPlatformStatus] +Meter=String +X=(3 * #IncrementButtonDimension#)r +Y=(#IncrementButtonDimension# / 2)r +W=((#WindowWidth# / 2) - 1) +H=#IncrementButtonDimension# +Text=Vertical +FontFace=Arial +FontSize=(#TabHeight#/3) +FontColor=#ButtonTextColor# +StringAlign=CenterCenter +StringEffect=Shadow +ClipString=1 +AntiAlias=1 +DynamicVariables=1 +Group=Layout + ;======================== Path settings ======================== ;------------------------ Steam path ------------------------ [SteamPathTitle] @@ -514,7 +551,7 @@ FontColor=255,255,255,255 FontFace=Arial StringAlign=Right FontSize=(#TabHeight#/3) -X=(2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) +X=(3 / 2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) Y=(1 * #TabHeight# + 10) W=(#WindowWidth# / 2) H=#IncrementButtonDimension# @@ -559,7 +596,7 @@ FontColor=255,255,255,255 FontFace=Arial StringAlign=Right FontSize=(#TabHeight#/3) -X=(2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) +X=(3 / 2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) Y=(2 * #TabHeight# + 10) W=(#WindowWidth# / 2) H=#IncrementButtonDimension# @@ -595,7 +632,7 @@ FontColor=255,255,255,255 FontFace=Arial StringAlign=Right FontSize=(#TabHeight#/3) -X=(2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) +X=(3 / 2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) Y=(3 * #TabHeight# + 10) W=(#WindowWidth# / 2) H=#IncrementButtonDimension# @@ -640,7 +677,7 @@ FontColor=255,255,255,255 FontFace=Arial StringAlign=Right FontSize=(#TabHeight#/3) -X=(2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) +X=(3 / 2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) Y=(4 * #TabHeight# + 10) W=(#WindowWidth# / 2) H=#IncrementButtonDimension# @@ -685,7 +722,7 @@ FontColor=255,255,255,255 FontFace=Arial StringAlign=Right FontSize=(#TabHeight#/3) -X=(2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) +X=(3 / 2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) Y=(5 * #TabHeight# + 10) W=(#WindowWidth# / 2) H=#IncrementButtonDimension# @@ -694,6 +731,78 @@ Command1=[!CommandMeasure "SettingsScript" "AcceptPythonPath('$UserInput$')"] DynamicVariables=1 Group=Paths +;------------------------ Start game bang ------------------------ +[StartGameBangTitle] +Meter=String +MeterStyle=PathOptionTitleTemplate +Y=(6 * #TabHeight# + 10 + (#IncrementButtonDimension# / 2)) +Text=Starting bang +ToolTipTitle=Starting bang +ToolTipText=This Rainmeter bang is executed whenever a game starts running. Bangs may not contain double, " , or single, ' , quotes and the grave accent (or backtick), ` , should be used instead! Multiple bangs can be executed, if each bang is enclosed by square brackets. + +[StartGameBangTextField] +Meter=Image +MeterStyle=PathTextFieldTemplate + +[StartGameBangStatus] +Meter=String +MeterStyle=PathStatusTemplate +Text= +LeftMouseUpAction=[!CommandMeasure "StartGameBangInput" "ExecuteBatch 1"] + +[StartGameBangInput] +Measure=Plugin +Plugin=InputText +SolidColor=#TextFieldColor# +FontColor=255,255,255,255 +FontFace=Arial +StringAlign=Right +FontSize=(#TabHeight#/3) +X=(3 / 2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) +Y=(6 * #TabHeight# + 10) +W=(#WindowWidth# / 2) +H=#IncrementButtonDimension# +DefaultValue= +Command1=[!CommandMeasure "SettingsScript" "AcceptStartGameBang('$UserInput$')"] +DynamicVariables=1 +Group=Paths + +;------------------------ Stop game bang ------------------------ +[StopGameBangTitle] +Meter=String +MeterStyle=PathOptionTitleTemplate +Y=(7 * #TabHeight# + 10 + (#IncrementButtonDimension# / 2)) +Text=Stopping bang +ToolTipTitle=Stopping bang +ToolTipText=This Rainmeter bang is executed whenever a game stops running. Bangs may not contain double, " , or single, ' , quotes and the grave accent (or backtick), ` , should be used instead! Multiple bangs can be executed, if each bang is enclosed by square brackets. + +[StopGameBangTextField] +Meter=Image +MeterStyle=PathTextFieldTemplate + +[StopGameBangStatus] +Meter=String +MeterStyle=PathStatusTemplate +Text= +LeftMouseUpAction=[!CommandMeasure "StopGameBangInput" "ExecuteBatch 1"] + +[StopGameBangInput] +Measure=Plugin +Plugin=InputText +SolidColor=#TextFieldColor# +FontColor=255,255,255,255 +FontFace=Arial +StringAlign=Right +FontSize=(#TabHeight#/3) +X=(3 / 2 * #IncrementButtonDimension# + #WindowWidth# / 4 + 20) +Y=(7 * #TabHeight# + 10) +W=(#WindowWidth# / 2) +H=#IncrementButtonDimension# +DefaultValue= +Command1=[!CommandMeasure "SettingsScript" "AcceptStopGameBang('$UserInput$')"] +DynamicVariables=1 +Group=Paths + ;======================== Save and exit buttons ======================== [SaveButton] Meter=Image diff --git a/Readme.md b/Readme.md index 3dfdfe7..4d403f2 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ Lauhdutin == -A Rainmeter skin for launching games. +A Rainmeter skin for launching games. Supports Steam, GOG Galaxy, and regular Windows shortcuts. ![ex](demo.gif) @@ -8,7 +8,9 @@ A Rainmeter skin for launching games. - [Requirements](#requirements) - [Installing](#installing) - [Updating](#updating) + - [Supported platforms](#supported-platforms) - [Filtering](#filtering) + - [Bangs](#bangs) - [Changelog](#changelog) - [License](#license) @@ -50,6 +52,24 @@ or - Extract the latest version of Lauhdutin over the old version's remaining barebones folder. Do not overwrite `PythonPath.inc`, if you left it intact when removing files and folders. Do not overwrite any custom icons you may have been using either, if you were using custom icons for e.g. showing how games are being sorted. - Load **Main.ini** in Rainmeter, right-click on the skin, go to **Custom skin actions**, and click on **Rebuild**. +# Supported platforms +Lauhdutin currently supports Steam and GOG Galaxy. + +Steam support includes: +- Acquire a list of installed games and games that are not currently installed, but for which a license has been purchased. +- Acquire a list of games that have been added to Steam as a 'non-Steam game'. +- Launch the games that were found by the features described above. +- Install Steam games that are not currently installed. +- Automatically download banners for Steam games that were found. +- Integrate the total amount of hours played that is tracked by Steam into Lauhdutin's corresponding system. + +GOG Galaxy support includes: +- Acquire a list of games installed via GOG Galaxy. +- Launch games that were found. +- Automatically download banners for games that were found. + +Additional platforms may receive similar support in the future, if possible. In the mean time it is possible to add games, which were not installed via the supported platforms described above, by placing a shortcut in `\Rainmeter\Skins\Lauhdutin\@Resources\Shortcuts` (banners can be placed in `\Rainmeter\Skins\Lauhdutin\@Resources\Banners\Shortcuts` with the same name as the shortcut). + # Filtering The list of games can be narrowed down by applying a filter. A filter can just be the name, or a part of the name, of one or more games. There are also special filters: @@ -67,7 +87,29 @@ The list of games can be narrowed down by applying a filter. A filter can just b Filters can be applied by left-clicking on the magnifying glass in the toolbar, which becomes visible when you nudge the top of the skin. Filters can be removed by either right-clicking on the magnifying glass or by applying a blank filter. +# Bangs +There are settings for executing [bangs](https://docs.rainmeter.net/manual/bangs/) under specific circumstances. Double, `"`, and single, `'`, quotation marks have to be replaced with grave accents (or backticks), ``` ` ```! Multiple bangs can be executed by enclosing each bang in square brackets (e.g. ```[!ActivateConfig `SomeConfigName`][!Log `Starting a game`]```). + +This feature can be used to e.g. load and unload skins. + +Currently supported events that can be used to trigger the execution of bangs: +- A game starts running. Works with any installed game that is listed in Lauhdutin. +- A game stops running. Works with any: + - Steam game, provided that the Steam in-game overlay setting is enabled in Steam. + - non-Steam game that has a process that can be tracked (i.e. Lauhdutin is capable of keeping track of how many hours have been spent playing the game). + # Changelog +**Version 2.3.0 - 2017/02/19:** +- Added overlay art for generic errors. +- Added overlays for invalid path errors for Steam and Windows shortcuts. +- Added setting for toggling the visibility of the platform in overlays. +- Added support for executing bangs when a game starts or stops running. +- Added settings for Rainmeter bangs that should be executed when a game starts and when a game stops running. +- Updated tooltips. +- Updated names of tabs in the skin for settings. +- Minor optimization of the GUI. +- Fixed layout of input fields in the skin for settings. + **Version 2.2.0 - 2017/02/10:** - Added support for tracking total amount of time played for most games. Will not work properly e.g. when the Battle.net client is opened instead of launching a game directly. Total time played is stored in `games.json`, which can be transferred from an older version to a newer version when updating. Supports Steam's time tracking, if a valid *SteamID64* value is specified in the settings. - Added support for processing Steam community profiles for additional information on games (e.g. hours played). Feature can be disabled by leaving the new *SteamID64* setting blank. diff --git a/Tests/RunTests.py b/Tests/RunTests.py index b98ece6..791bc16 100644 --- a/Tests/RunTests.py +++ b/Tests/RunTests.py @@ -34,6 +34,8 @@ def test_get_games(self): self.assertEqual(ws.get_games(), { "Office Suite 2015": { GameKeys.NAME: "Office Suite 2015", + GameKeys.ERROR: True, + GameKeys.INVALID_PATH: True, GameKeys.PATH: "D:\\Program Files (x86)\\Office Suite 2015\\vERsion_1_52_8.exe", GameKeys.LASTPLAYED: 0, @@ -42,6 +44,8 @@ def test_get_games(self): }, "Office Suite 2017": { GameKeys.NAME: "Office Suite 2017", + GameKeys.ERROR: True, + GameKeys.INVALID_PATH: True, GameKeys.PATH: "D:\\Program Files (x86)\\Office Suite 2017\\version 2.4.53.exe", GameKeys.LASTPLAYED: 0, @@ -50,6 +54,8 @@ def test_get_games(self): }, "Overwatch": { GameKeys.NAME: "Overwatch", + GameKeys.ERROR: True, + GameKeys.INVALID_PATH: True, GameKeys.PATH: "D:\\Program Files\\Battle.net Games\\Overwatch\\Overwatch.exe", GameKeys.LASTPLAYED: 0, @@ -69,6 +75,8 @@ def test_process_shortcut(self): ws.process_shortcut("Office Suite 2015.lnk"), ("Office Suite 2015", { GameKeys.NAME: "Office Suite 2015", + GameKeys.ERROR: True, + GameKeys.INVALID_PATH: True, GameKeys.PATH: "D:\\Program Files (x86)\\Office Suite 2015\\vERsion_1_52_8.exe", GameKeys.LASTPLAYED: 0, @@ -79,6 +87,8 @@ def test_process_shortcut(self): ws.process_shortcut("Office Suite 2017.lnk"), ("Office Suite 2017", { GameKeys.NAME: "Office Suite 2017", + GameKeys.ERROR: True, + GameKeys.INVALID_PATH: True, GameKeys.PATH: "D:\\Program Files (x86)\\Office Suite 2017\\version 2.4.53.exe", GameKeys.LASTPLAYED: 0, @@ -88,6 +98,8 @@ def test_process_shortcut(self): self.assertEqual( ws.process_shortcut("Overwatch.lnk"), ("Overwatch", { GameKeys.NAME: "Overwatch", + GameKeys.ERROR: True, + GameKeys.INVALID_PATH: True, GameKeys.PATH: "D:\\Program Files\\Battle.net Games\\Overwatch\\Overwatch.exe", GameKeys.LASTPLAYED: 0, @@ -161,53 +173,44 @@ def test_get_games(self): steam = self.create_class_instance() self.assertEqual(steam.get_games(), { '206190': { - 'platform': 0, - 'path': 'steam://rungameid/206190', - 'title': 'Gunpoint', - 'banner': 'Steam\\206190.jpg', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.PATH: 'steam://rungameid/206190', + GameKeys.NAME: 'Gunpoint', + GameKeys.BANNER_PATH: 'Steam\\206190.jpg', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/206190/header.jpg', - 'lastplayed': '1483391006' + GameKeys.LASTPLAYED: '1483391006' }, '212680': { - 'platform': 0, - 'path': 'steam://rungameid/212680', - 'title': 'FTL: Faster Than Light', - 'banner': 'Steam\\212680.jpg', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.PATH: 'steam://rungameid/212680', + GameKeys.NAME: 'FTL: Faster Than Light', + GameKeys.BANNER_PATH: 'Steam\\212680.jpg', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/212680/header.jpg', - 'lastplayed': '1485649993', + GameKeys.LASTPLAYED: '1485649993', 'tags': { '0': 'Not completed' } }, '40700': { - 'platform': 0, - 'path': 'steam://rungameid/40700', - 'title': 'Machinarium', - 'banner': 'Steam\\40700.jpg', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.PATH: 'steam://rungameid/40700', + GameKeys.NAME: 'Machinarium', + GameKeys.BANNER_PATH: 'Steam\\40700.jpg', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/40700/header.jpg', - 'lastplayed': '1351494000', + GameKeys.LASTPLAYED: '1351494000', 'tags': { '0': 'Not completed' } - }, - '26800': { - 'platform': 0, - 'path': 'steam://rungameid/26800', - 'title': 'Braid', - 'banner': 'Steam\\26800.jpg', - 'bannerurl': - 'http://cdn.akamai.steamstatic.com/steam/apps/26800/header.jpg', - 'lastplayed': 0 } }) def test_get_libraries(self): steam = self.create_class_instance() self.assertEqual( - steam.get_libraries(STEAM_PATH), [STEAM_PATH, 'G:\\SteamLibrary']) + steam.get_libraries(STEAM_PATH), [STEAM_PATH, 'X:\\SteamLibrary']) def test_get_shared_config(self): steam = self.create_class_instance() @@ -531,64 +534,64 @@ def test_get_installed_game(self): appmanifest_paths.extend( steam.get_appmanifest_paths(STEAM_LIBRARY_PATH)) expected_results = [{ - 'platform': 0, - 'path': 'steam://rungameid/206190', - 'title': 'Gunpoint', - 'banner': 'Steam\\206190.jpg', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.PATH: 'steam://rungameid/206190', + GameKeys.NAME: 'Gunpoint', + GameKeys.BANNER_PATH: 'Steam\\206190.jpg', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/206190/header.jpg', - 'lastplayed': '1483391006', - 'hourslast2weeks': 0, - 'hourstotal': 2.0 + GameKeys.LASTPLAYED: '1483391006', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 2.0 }, { - 'platform': 0, - 'path': 'steam://rungameid/212680', - 'title': 'FTL: Faster Than Light', - 'banner': 'Steam\\212680.jpg', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.PATH: 'steam://rungameid/212680', + GameKeys.NAME: 'FTL: Faster Than Light', + GameKeys.BANNER_PATH: 'Steam\\212680.jpg', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/212680/header.jpg', - 'lastplayed': '1485649993', - 'tags': { + GameKeys.LASTPLAYED: '1485649993', + GameKeys.TAGS: { '0': 'Not completed' }, - 'hourslast2weeks': 0, - 'hourstotal': 14.4 + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 14.4 }, { - 'platform': 0, - 'path': 'steam://rungameid/40700', - 'title': 'Machinarium', - 'banner': 'Steam\\40700.jpg', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.PATH: 'steam://rungameid/40700', + GameKeys.NAME: 'Machinarium', + GameKeys.BANNER_PATH: 'Steam\\40700.jpg', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/40700/header.jpg', - 'lastplayed': '1351494000', - 'tags': { + GameKeys.LASTPLAYED: '1351494000', + GameKeys.TAGS: { '0': 'Not completed' }, - 'hourslast2weeks': 0, - 'hourstotal': 2.5 + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 2.5 }, { - 'platform': 0, - 'path': 'steam://rungameid/219150', - 'title': 'Hotline Miami', - 'banner': 'Steam\\219150.jpg', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.PATH: 'steam://rungameid/219150', + GameKeys.NAME: 'Hotline Miami', + GameKeys.BANNER_PATH: 'Steam\\219150.jpg', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/219150/header.jpg', - 'lastplayed': '1483391126', - 'hourslast2weeks': 0, - 'hourstotal': 4.6 + GameKeys.LASTPLAYED: '1483391126', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 4.6 }, { - 'platform': 0, - 'path': 'steam://rungameid/250900', - 'title': 'Binding of Isaac: Rebirth, The', - 'banner': 'Steam\\250900.jpg', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.PATH: 'steam://rungameid/250900', + GameKeys.NAME: 'Binding of Isaac: Rebirth, The', + GameKeys.BANNER_PATH: 'Steam\\250900.jpg', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/250900/header.jpg', - 'lastplayed': '1483487840', - 'tags': { + GameKeys.LASTPLAYED: '1483487840', + GameKeys.TAGS: { '0': 'Not completed' }, - 'hourslast2weeks': 0, - 'hourstotal': 528.2 + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 528.2 }, None] appmanifests = [ steam.get_appmanifest(appmanifest_path) @@ -678,117 +681,117 @@ def test_get_not_installed_game(self): game_definitions = steam.parse_community_profile(decoded_lines) app_ids = [app_id for app_id in game_definitions] expected_results = [{ - 'platform': 0, - 'notinstalled': True, - 'title': 'Machinarium', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.NOT_INSTALLED: True, + GameKeys.NAME: 'Machinarium', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/40700/header.jpg', - 'banner': 'Steam\\40700.jpg', - 'lastplayed': '1351494000', - 'path': 'steam://rungameid/40700', - 'hourslast2weeks': 0, - 'hourstotal': 2.5, - 'tags': { + GameKeys.BANNER_PATH: 'Steam\\40700.jpg', + GameKeys.LASTPLAYED: '1351494000', + GameKeys.PATH: 'steam://rungameid/40700', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 2.5, + GameKeys.TAGS: { '0': 'Not completed' } }, { - 'platform': 0, - 'notinstalled': True, - 'title': 'Gunpoint', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.NOT_INSTALLED: True, + GameKeys.NAME: 'Gunpoint', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/206190/header.jpg', - 'banner': 'Steam\\206190.jpg', - 'lastplayed': '1483391006', - 'path': 'steam://rungameid/206190', - 'hourslast2weeks': 0, - 'hourstotal': 2.0 + GameKeys.BANNER_PATH: 'Steam\\206190.jpg', + GameKeys.LASTPLAYED: '1483391006', + GameKeys.PATH: 'steam://rungameid/206190', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 2.0 }, { - 'platform': 0, - 'notinstalled': True, - 'title': 'FTL: Faster Than Light', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.NOT_INSTALLED: True, + GameKeys.NAME: 'FTL: Faster Than Light', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/212680/header.jpg', - 'banner': 'Steam\\212680.jpg', - 'lastplayed': '1485649993', - 'path': 'steam://rungameid/212680', - 'hourslast2weeks': 0, - 'hourstotal': 14.4, - 'tags': { + GameKeys.BANNER_PATH: 'Steam\\212680.jpg', + GameKeys.LASTPLAYED: '1485649993', + GameKeys.PATH: 'steam://rungameid/212680', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 14.4, + GameKeys.TAGS: { '0': 'Not completed' } }, { - 'platform': 0, - 'notinstalled': True, - 'title': 'Hotline Miami', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.NOT_INSTALLED: True, + GameKeys.NAME: 'Hotline Miami', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/219150/header.jpg', - 'banner': 'Steam\\219150.jpg', - 'lastplayed': '1483391126', - 'path': 'steam://rungameid/219150', - 'hourslast2weeks': 0, - 'hourstotal': 4.6 + GameKeys.BANNER_PATH: 'Steam\\219150.jpg', + GameKeys.LASTPLAYED: '1483391126', + GameKeys.PATH: 'steam://rungameid/219150', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 4.6 }, { - 'platform': 0, - 'notinstalled': True, - 'title': 'Binding of Isaac: Rebirth, The', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.NOT_INSTALLED: True, + GameKeys.NAME: 'Binding of Isaac: Rebirth, The', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/250900/header.jpg', - 'banner': 'Steam\\250900.jpg', - 'lastplayed': '1483487840', - 'path': 'steam://rungameid/250900', - 'hourslast2weeks': 0, - 'hourstotal': 528.2, - 'tags': { + GameKeys.BANNER_PATH: 'Steam\\250900.jpg', + GameKeys.LASTPLAYED: '1483487840', + GameKeys.PATH: 'steam://rungameid/250900', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 528.2, + GameKeys.TAGS: { '0': 'Not completed' } }, { - 'platform': 0, - 'notinstalled': True, - 'title': "Oddworld: Abe's Oddysee", - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.NOT_INSTALLED: True, + GameKeys.NAME: "Oddworld: Abe's Oddysee", + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/15700/header.jpg', - 'banner': 'Steam\\15700.jpg', - 'lastplayed': '1462968923', - 'path': 'steam://rungameid/15700', - 'hourslast2weeks': 0, - 'hourstotal': 0, - 'tags': { + GameKeys.BANNER_PATH: 'Steam\\15700.jpg', + GameKeys.LASTPLAYED: '1462968923', + GameKeys.PATH: 'steam://rungameid/15700', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 0, + GameKeys.TAGS: { '0': 'Not completed' } }, { - 'platform': 0, - 'notinstalled': True, - 'title': 'Dragon Age: Origins', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.NOT_INSTALLED: True, + GameKeys.NAME: 'Dragon Age: Origins', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/17450/header.jpg', - 'banner': 'Steam\\17450.jpg', - 'lastplayed': '1417274465', - 'path': 'steam://rungameid/17450', - 'hourslast2weeks': 0, - 'hourstotal': 124.4 + GameKeys.BANNER_PATH: 'Steam\\17450.jpg', + GameKeys.LASTPLAYED: '1417274465', + GameKeys.PATH: 'steam://rungameid/17450', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 124.4 }, { - 'platform': 0, - 'notinstalled': True, - 'title': 'Zombie Panic! Source', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.NOT_INSTALLED: True, + GameKeys.NAME: 'Zombie Panic! Source', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/17500/header.jpg', - 'banner': 'Steam\\17500.jpg', - 'lastplayed': '1271009838', - 'path': 'steam://rungameid/17500', - 'hourslast2weeks': 0, - 'hourstotal': 0.2 + GameKeys.BANNER_PATH: 'Steam\\17500.jpg', + GameKeys.LASTPLAYED: '1271009838', + GameKeys.PATH: 'steam://rungameid/17500', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 0.2 }, { - 'platform': 0, - 'notinstalled': True, - 'title': 'Red Faction: Guerrilla Steam Edition', - 'bannerurl': + GameKeys.PLATFORM: 0, + GameKeys.NOT_INSTALLED: True, + GameKeys.NAME: 'Red Faction: Guerrilla Steam Edition', + GameKeys.BANNER_URL: 'http://cdn.akamai.steamstatic.com/steam/apps/20500/header.jpg', - 'banner': 'Steam\\20500.jpg', - 'lastplayed': '1428684708', - 'path': 'steam://rungameid/20500', - 'hourslast2weeks': 0, - 'hourstotal': 2.6, - 'tags': { + GameKeys.BANNER_PATH: 'Steam\\20500.jpg', + GameKeys.LASTPLAYED: '1428684708', + GameKeys.PATH: 'steam://rungameid/20500', + GameKeys.HOURS_LAST_TWO_WEEKS: 0, + GameKeys.HOURS_TOTAL: 2.6, + GameKeys.TAGS: { '0': 'Not completed' } }] @@ -805,30 +808,36 @@ def test_get_shortcuts(self): steam = self.create_class_instance() self.assertEqual(steam.get_shortcuts(), { '0': { - 'platform': 1, - 'lastplayed': 0, - 'title': 'RealTemp', - 'banner': 'Steam shortcuts\\RealTemp.jpg', - 'path': 'steam://rungameid/17906321180839641088' + GameKeys.PLATFORM: 1, + GameKeys.LASTPLAYED: 0, + GameKeys.NAME: 'RealTemp', + GameKeys.BANNER_PATH: 'Steam shortcuts\\RealTemp.jpg', + GameKeys.PATH: 'steam://rungameid/10040859602154684416', + GameKeys.ERROR: True, + GameKeys.INVALID_PATH: True }, '1': { - 'platform': 1, - 'lastplayed': 0, - 'title': 'GPU-Z', - 'banner': 'Steam shortcuts\\GPU-Z.jpg', - 'path': 'steam://rungameid/11616125968489381888', - 'tags': { + GameKeys.PLATFORM: 1, + GameKeys.LASTPLAYED: 0, + GameKeys.NAME: 'GPU-Z', + GameKeys.BANNER_PATH: 'Steam shortcuts\\GPU-Z.jpg', + GameKeys.PATH: 'steam://rungameid/18383980479696076800', + GameKeys.ERROR: True, + GameKeys.INVALID_PATH: True, + GameKeys.TAGS: { '0': 'GPU', '1': 'Utility' } }, '2': { - 'platform': 1, - 'lastplayed': 0, - 'title': 'CPU-Z', - 'banner': 'Steam shortcuts\\CPU-Z.jpg', - 'path': 'steam://rungameid/13161530333453090816', - 'tags': { + GameKeys.PLATFORM: 1, + GameKeys.LASTPLAYED: 0, + GameKeys.NAME: 'CPU-Z', + GameKeys.BANNER_PATH: 'Steam shortcuts\\CPU-Z.jpg', + GameKeys.PATH: 'steam://rungameid/11463541207985029120', + GameKeys.ERROR: True, + GameKeys.INVALID_PATH: True, + GameKeys.TAGS: { '0': 'CPU', '1': 'Utility' } @@ -839,7 +848,7 @@ def test_read_shortcuts_file(self): steam = self.create_class_instance() self.assertEqual( steam.read_shortcuts_file(STEAM_PATH, STEAM_USERDATAID), - '|shortcuts||0||AppName|CPU-Z||exe|"D:\\Programs\\CPU-Z\\cpuz_x64.exe"||StartDir|"D:\\Programs\\CPU-Z\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags||0|CPU||1|Utility||||1||AppName|GPU-Z||exe|"D:\\Programs\\GPU-Z\\GPU-Z.1.17.0.exe"||StartDir|"D:\\Programs\\GPU-Z\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags||0|GPU||1|Utility||||2||AppName|RealTemp||exe|"D:\\Programs\\RealTemp\\RealTemp.exe"||StartDir|"D:\\Programs\\RealTemp\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags|||||' + '|shortcuts||0||AppName|CPU-Z||exe|"X:\\Programs\\CPU-Z\\cpuz_x64.exe"||StartDir|"X:\\Programs\\CPU-Z\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags||0|CPU||1|Utility||||1||AppName|GPU-Z||exe|"X:\\Programs\\GPU-Z\\GPU-Z.1.17.0.exe"||StartDir|"X:\\Programs\\GPU-Z\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags||0|GPU||1|Utility||||2||AppName|RealTemp||exe|"X:\\Programs\\RealTemp\\RealTemp.exe"||StartDir|"X:\\Programs\\RealTemp\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags|||||' ) def test_parse_shortcuts_string(self): @@ -848,11 +857,11 @@ def test_parse_shortcuts_string(self): self.assertEqual( steam.parse_shortcuts_string(output), { '0': - '|AppName|RealTemp||exe|"D:\\Programs\\RealTemp\\RealTemp.exe"||StartDir|"D:\\Programs\\RealTemp\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags|||||', + '|AppName|RealTemp||exe|"X:\\Programs\\RealTemp\\RealTemp.exe"||StartDir|"X:\\Programs\\RealTemp\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags|||||', '1': - '|AppName|GPU-Z||exe|"D:\\Programs\\GPU-Z\\GPU-Z.1.17.0.exe"||StartDir|"D:\\Programs\\GPU-Z\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags||0|GPU||1|Utility||||2|', + '|AppName|GPU-Z||exe|"X:\\Programs\\GPU-Z\\GPU-Z.1.17.0.exe"||StartDir|"X:\\Programs\\GPU-Z\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags||0|GPU||1|Utility||||2|', '2': - '|AppName|CPU-Z||exe|"D:\\Programs\\CPU-Z\\cpuz_x64.exe"||StartDir|"D:\\Programs\\CPU-Z\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags||0|CPU||1|Utility||||1|' + '|AppName|CPU-Z||exe|"X:\\Programs\\CPU-Z\\cpuz_x64.exe"||StartDir|"X:\\Programs\\CPU-Z\\"||icon|||ShortcutPath|||IsHidden||||||AllowDesktopConfig||||||OpenVR||||||tags||0|CPU||1|Utility||||1|' }) def test_parse_shortcut_title(self): @@ -872,13 +881,13 @@ def test_parse_shortcut_path(self): steam.read_shortcuts_file(STEAM_PATH, STEAM_USERDATAID)) name, shortcut = steam.parse_shortcut_title(shortcuts["0"]) path, _ = steam.parse_shortcut_path(shortcut) - self.assertEqual(path, "D:\\Programs\\RealTemp\\RealTemp.exe") + self.assertEqual(path, "X:\\Programs\\RealTemp\\RealTemp.exe") name, shortcut = steam.parse_shortcut_title(shortcuts["1"]) path, _ = steam.parse_shortcut_path(shortcut) - self.assertEqual(path, "D:\\Programs\\GPU-Z\\GPU-Z.1.17.0.exe") + self.assertEqual(path, "X:\\Programs\\GPU-Z\\GPU-Z.1.17.0.exe") name, shortcut = steam.parse_shortcut_title(shortcuts["2"]) path, _ = steam.parse_shortcut_path(shortcut) - self.assertEqual(path, "D:\\Programs\\CPU-Z\\cpuz_x64.exe") + self.assertEqual(path, "X:\\Programs\\CPU-Z\\cpuz_x64.exe") def test_parse_shortcut_app_id(self): steam = self.create_class_instance() @@ -887,15 +896,15 @@ def test_parse_shortcut_app_id(self): name, shortcut = steam.parse_shortcut_title(shortcuts["0"]) path, shortcut = steam.parse_shortcut_path(shortcut) app_id = steam.parse_shortcut_app_id(path, name) - self.assertEqual(app_id, 17906321180839641088) + self.assertEqual(app_id, 10040859602154684416) name, shortcut = steam.parse_shortcut_title(shortcuts["1"]) path, shortcut = steam.parse_shortcut_path(shortcut) app_id = steam.parse_shortcut_app_id(path, name) - self.assertEqual(app_id, 11616125968489381888) + self.assertEqual(app_id, 18383980479696076800) name, shortcut = steam.parse_shortcut_title(shortcuts["2"]) path, shortcut = steam.parse_shortcut_path(shortcut) app_id = steam.parse_shortcut_app_id(path, name) - self.assertEqual(app_id, 13161530333453090816) + self.assertEqual(app_id, 11463541207985029120) def test_parse_shortcut_tags(self): steam = self.create_class_instance() diff --git a/Tests/Steam/steamapps/libraryfolders.vdf b/Tests/Steam/steamapps/libraryfolders.vdf index b9a2b70..b016688 100644 --- a/Tests/Steam/steamapps/libraryfolders.vdf +++ b/Tests/Steam/steamapps/libraryfolders.vdf @@ -2,5 +2,5 @@ { "TimeNextStatsReport" "1486586443" "ContentStatsID" "-6329368787253216991" - "1" "G:\\SteamLibrary" + "1" "X:\\SteamLibrary" } diff --git a/Tests/Steam/userdata/0123456789/config/shortcuts.vdf b/Tests/Steam/userdata/0123456789/config/shortcuts.vdf index 830d7b5..8b8480e 100644 Binary files a/Tests/Steam/userdata/0123456789/config/shortcuts.vdf and b/Tests/Steam/userdata/0123456789/config/shortcuts.vdf differ