10 Commits

Author SHA1 Message Date
LunaChocken 26840e7a40 added timing
Package Application with PyInstaller / build (push) Successful in 27s
2025-06-09 18:02:02 +01:00
LunaChocken 153bf640be add caching
Package Application with PyInstaller / build (push) Successful in 26s
2025-06-09 17:26:44 +01:00
LunaChocken 711579e2b1 rename file
Package Application with PyInstaller / build (push) Successful in 27s
2025-06-09 16:10:22 +01:00
LunaChocken a4f0e5eece add caching
Package Application with PyInstaller / build (push) Failing after 45s
2025-06-09 16:07:29 +01:00
LunaChocken d8a49d04a3 change name of executable
Package Application with PyInstaller / build (push) Has been cancelled
2025-06-09 14:53:01 +01:00
LunaChocken 9c2073f1ad fix acf_path having "dir" indicator and not file
Package Application with PyInstaller / build (push) Successful in 27s
2025-06-08 23:02:33 +01:00
LunaChocken 4c39ab90dc Refactor game info display with TableItem class
Package Application with PyInstaller / build (push) Successful in 28s
2025-06-08 20:34:36 +01:00
LunaChocken 10e4b73b00 add copy of gitea workflow to github folder workflows
Package Application with PyInstaller / build (push) Successful in 27s
2025-06-08 20:04:39 +01:00
LunaChocken e3c35285f2 - Add all command to display All games
Package Application with PyInstaller / build (push) Successful in 26s
- Remove printing all games immediately
2025-06-08 19:30:10 +01:00
LunaChocken 02731ad9ca Disable release builder. Doesnt work
Package Application with PyInstaller / build (push) Successful in 31s
Add ctrl+C better support using try except statements
Add workshop paths
2025-06-07 23:52:05 +01:00
11 changed files with 297 additions and 86 deletions
+4 -6
View File
@@ -7,14 +7,13 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: '3.11.0' python-version: "3.11.0"
- name: Install dependencies - name: Install dependencies
run: > run: >
@@ -24,11 +23,10 @@ jobs:
- name: Package Application with PyInstaller - name: Package Application with PyInstaller
run: | run: |
pyinstaller steamPathCLI.spec pyinstaller spath.spec
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: steamPathCLI.sh name: spath.sh
path: dist/steamPathCLI.sh path: dist/spath.sh
+7 -5
View File
@@ -1,7 +1,9 @@
# DISABLED
name: release name: release
on: # on:
workflow_dispatch: # workflow_dispatch:
jobs: jobs:
release: release:
@@ -16,7 +18,7 @@ jobs:
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: '3.11.0' python-version: "3.11.0"
- name: Install dependencies - name: Install dependencies
run: > run: >
python -m pip install --upgrade pip python -m pip install --upgrade pip
@@ -25,9 +27,9 @@ jobs:
- name: Package Application with PyInstaller - name: Package Application with PyInstaller
run: | run: |
pyinstaller steamPathCLI.spec pyinstaller spath.spec
uses: https://gitea.com/actions/release-action@main uses: https://gitea.com/actions/release-action@main
with: with:
files: |- files: |-
dist/** dist/**
api_key: '${{secrets.RELEASE_TOKEN}}' api_key: "${{secrets.RELEASE_TOKEN}}"
+32
View File
@@ -0,0 +1,32 @@
name: Package Application with PyInstaller
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11.0"
- name: Install dependencies
run: >
python -m pip install --upgrade pip
pip install . # Install dependencies; modify if using requirements.txt
- name: Package Application with PyInstaller
run: |
pyinstaller spath.spec
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: spath.sh
path: dist/spath.sh
+116 -22
View File
@@ -6,47 +6,121 @@ from rich.columns import Columns
from rich.panel import Panel from rich.panel import Panel
import src.vdfparser as vd import src.vdfparser as vd
from src.prompt_helper import PromptHelper from src.prompt_helper import PromptHelper
# Commandline options support
import argparse
# basic attempt at making program faster
import datetime
from src.timing import timeit
from cachier import cachier
cachier = cachier(stale_after=datetime.timedelta(days=1), cache_dir='/tmp/.cache')
class TableItem:
def __init__(self, name, data='', colour='white', type='desc'):
self.name = name
self.data = data
self.type = type
self.colour = colour
def generate_link(self):
if self.type == 'file':
return f"[{self.colour}][link=file://{self.data}]file[/link][/{self.colour}]"
elif self.type == 'dir':
return f"[{self.colour}][link=file://{self.data}]dir[/link][/{self.colour}]"
else:
return f"[{self.colour}]{self.data}[/{self.colour}]"
def __str__(self):
return f"\n[white]{self.name}[/white]: [{self.colour}]"+self.generate_link()+""
class SteamGamePathTool: class SteamGamePathTool:
def __init__(self): # arg mode means user input will be skipped and take all args from command line
self.steam_path = vd.fetch_steam_path() def __init__(self, steamPath=vd.fetch_steam_path(), arg_mode_enabled=None, game_name=None, game_id=None, all=False):
self.steam_path = steamPath
self.steam_vdf_path = vd.fetch_steam_vdf() self.steam_vdf_path = vd.fetch_steam_vdf()
# arg support
self.arg_mode_enabled = arg_mode_enabled
self.game_name = game_name
self.game_id = game_id
self.all = all
if self.steam_vdf_path is None: if self.steam_vdf_path is None:
print("Steam VDF file not found") print("Steam VDF file not found")
# Add user input to attempt to find # Add user input to attempt to find
self.steam_vdf_path = prompt("Enter the path to the Steam VDF file: ", default=self.steam_path) self.steam_vdf_path = prompt("Enter the path to the Steam VDF file: ", default=self.steam_path)
# Fetch steam's vdf file and convert to json dict
self.steam_vdf = vd.parse_vdf(self.steam_vdf_path) self.steam_vdf = vd.parse_vdf(self.steam_vdf_path)
# Possible other locations where steamlibrary could be found
self.steam_library_locations = vd.find_extra_locations(self.steam_vdf) self.steam_library_locations = vd.find_extra_locations(self.steam_vdf)
games = vd.fetchall_vdfs(self.steam_vdf) games = vd.fetchall_vdfs(self.steam_vdf)
games = self.sort_games(games) self.games = self.sort_games(games)
console = Console()
game_rend = [Panel(self.get_game_content(game), expand=True) for game in games]
console.print(Columns(game_rend))
self.prompter = PromptHelper(games)
for library in self.steam_library_locations: for library in self.steam_library_locations:
print(f"[+] Found Steam library at: {library}") print(f"[+] Found Steam library at: {library}")
self.prompter = PromptHelper(games) if arg_mode_enabled:
self.arg_mode()
return
while True: while True:
self.prompt_user() self.prompt_user()
input("Press Enter to continue...") try:
input("Press Enter to continue...")
except KeyboardInterrupt:
print("\nExiting...")
break
def prompt_user(self): def arg_mode(self):
game = self.prompter.prompt_game(text="Input (game name | appid | q/quit): ") if self.all:
if game is None: console = Console()
game_rend = [Panel(self.get_game_content(game), expand=True) for game in self.games]
console.print(Columns(game_rend))
return
if self.game_id:
game = self.prompter.find_game_num(self.game_id)
elif self.game_name:
game = self.prompter.find_game_str(self.game_name)
else:
return return
console = Console() console = Console()
console.print(Panel(self.get_game_content(game), expand=True)) data = self.get_game_content(game)
if data:
console.print(Panel(data, expand=True))
else:
console.print("No game found")
@timeit
@cachier
def prepare_all_games(self):
game_rend = [Panel(self.get_game_content(game), expand=True) for game in self.games]
return game_rend
def print_all_games(self):
game_rend = self.prepare_all_games()
console = Console()
console.print(Columns(game_rend))
def prompt_user(self):
game = self.prompter.prompt_game(text="Input (game name | appid | all | q/quit): ")
if game is None:
return
elif game == 'fetch_all_games':
self.print_all_games()
else:
console = Console()
console.print(Panel(self.get_game_content(game), expand=True))
def sort_games(self, games): def sort_games(self, games):
return sorted(games, key=lambda x: x['name']) return sorted(games, key=lambda x: x['name'])
@cachier
def get_game_content(self, game): def get_game_content(self, game):
""" """
Takes a game dictionary and returns a string that formats game information into a string renderable by the console in the rich library. Takes a game dictionary and returns a string that formats game information into a string renderable by the console in the rich library.
@@ -55,14 +129,34 @@ class SteamGamePathTool:
:return: string formatted for table using rich library :return: string formatted for table using rich library
""" """
# Spaces must be replaced with %20 otherwise they won't link properly # Spaces must be replaced with %20 otherwise they won't link properly
try:
string = f"""[b]{game['name']}[/b] string = f"""[b]{game['name']}[/b]"""
[white]Game ID: [yellow]{game['appid']} string+=str(TableItem(name="Game ID", data=f"{game['appid']}", colour="blue",type="desc"))
[white]Game Size: [red]{int(game['SizeOnDisk'])/(1024*1024)/1024:.2f} GB[/red] string+=str(TableItem(name="Game acf", data=f"{game['acf_path'].replace(' ', '%20')}", colour="green",type="file"))
[white]Game acf: [green][link=file://{game['acf_path'].replace(' ', '%20')}]file[/link][/green] string+=str(TableItem(name="Game Path", data=f"{game['true_path'].replace(' ', '%20')}", colour="blue",type="dir"))
[white]Game Path: [green][link=file://{game['true_path'].replace(' ', '%20')}]dir[/link][/green]""" if game['workshop_path']:
if game['compatdata_path']: string+=str(TableItem(name="Game Workshop Path", data=f"{game['workshop_path'].replace(' ', '%20')}", colour="blue", type="dir"))
string += f"\n\t[white]Compatdata dir: [blue][link=file://{game['compatdata_path'].replace(' ', '%20')}]dir[/link][/blue]" if game["compatdata_path"]:
string+=str(TableItem(name="Game Compatdata Path",data=f"{game['compatdata_path'].replace(' ', '%20')}",colour="blue",type="dir"))
except TypeError:
return None
return string return string
if __name__ == "__main__": if __name__ == "__main__":
steam_path_tool = SteamGamePathTool() print("""Welcome to S-Path
A tool to print the locations of steam games, their respective gameID, workshop path, etc.""")
parser = argparse.ArgumentParser()
parser.add_argument('--name', help='Game name to search for')
parser.add_argument('--id', help='Game ID to search for')
# parser.add_argument('--help', help='Display help message')
parser.add_argument('--steam-path', help='Steam path to use')
parser.add_argument('--all', help='Displays all games installed', action='store_true')
args = parser.parse_args()
if args.name or args.id or args.all:
steam_path_tool = SteamGamePathTool(game_id=args.id, game_name=args.name, arg_mode_enabled=True, all=args.all)
else:
steam_path_tool = SteamGamePathTool()
+1
View File
@@ -5,6 +5,7 @@ description = "Add your description here"
readme = "README.md" readme = "README.md"
requires-python = ">=3.11" requires-python = ">=3.11"
dependencies = [ dependencies = [
"cachier>=3.1.2",
"prompt-toolkit>=3.0.51", "prompt-toolkit>=3.0.51",
"pyinstaller>=6.14.0", "pyinstaller>=6.14.0",
"rich>=14.0.0", "rich>=14.0.0",
+5 -2
View File
@@ -1,11 +1,14 @@
# -*- mode: python ; coding: utf-8 -*- # -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_data_files
datas = []
datas += collect_data_files('cachier')
a = Analysis( a = Analysis(
['main.py'], ['main.py'],
pathex=[], pathex=[],
binaries=[], binaries=[],
datas=[], datas=datas,
hiddenimports=[], hiddenimports=[],
hookspath=[], hookspath=[],
hooksconfig={}, hooksconfig={},
@@ -22,7 +25,7 @@ exe = EXE(
a.binaries, a.binaries,
a.datas, a.datas,
[], [],
name='main', name='spath.sh',
debug=False, debug=False,
bootloader_ignore_signals=False, bootloader_ignore_signals=False,
strip=False, strip=False,
+34 -11
View File
@@ -1,11 +1,19 @@
import prompt_toolkit as pt import prompt_toolkit as pt
from prompt_toolkit.completion import WordCompleter, FuzzyCompleter from prompt_toolkit.completion import WordCompleter, FuzzyCompleter
import sys import sys
import datetime
from src.timing import timeit
from cachier import cachier
cachier = cachier(stale_after=datetime.timedelta(days=1), cache_dir='/tmp/.cache')
@timeit
@cachier
def generate_completer(game_list): def generate_completer(game_list):
g_list = [x['name'] for x in game_list] + [x['appid'] for x in game_list] g_list = [x['name'] for x in game_list] + [x['appid'] for x in game_list]
g_list.append("q") g_list.append("q")
g_list.append("quit") g_list.append("quit")
g_list.append("all")
return FuzzyCompleter(WordCompleter(g_list)) return FuzzyCompleter(WordCompleter(g_list))
class PromptHelper: class PromptHelper:
@@ -13,11 +21,16 @@ class PromptHelper:
self.game_list = game_list self.game_list = game_list
self.completer = generate_completer(game_list) self.completer = generate_completer(game_list)
def find_game_str(self, game_name): @timeit
@cachier
def find_game_str(self, game_name) -> dict|None:
for game in self.game_list: for game in self.game_list:
if game['name'] == game_name: if game['name'] == game_name:
return game return game
def find_game_num(self, appid: str):
@timeit
@cachier
def find_game_num(self, appid: str) -> dict|None:
for game in self.game_list: for game in self.game_list:
if game['appid'] == appid: if game['appid'] == appid:
return game return game
@@ -25,13 +38,23 @@ class PromptHelper:
return None return None
def prompt_game(self, text, default="None"): def prompt_game(self, text, default="None"):
response = pt.prompt(text, completer=self.completer, complete_while_typing=True) try:
if response == "": response = pt.prompt(text, completer=self.completer, complete_while_typing=True)
return None except KeyboardInterrupt:
elif response == "q" or response == "quit": print("\nCtrl+C received. Exiting.")
print("Goodbye!")
sys.exit(0) sys.exit(0)
elif response[0].isalpha(): try:
return self.find_game_str(response) if response == "":
else: return None
return self.find_game_num(response) elif response == "all":
return "fetch_all_games"
elif response == "q" or response == "quit":
print("Goodbye!")
sys.exit(0)
elif response[0].isalpha():
return self.find_game_str(response)
else:
return self.find_game_num(response)
except ValueError:
print("Invalid input")
return None
+16
View File
@@ -0,0 +1,16 @@
from functools import wraps
import time
debug = True
def timeit(func):
@wraps(func)
def timeit_wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
total_time = end_time - start_time
if debug:
print(f'Function {func.__name__} Took {total_time:.4f} seconds.')
return result
return timeit_wrapper
+10
View File
@@ -1,6 +1,12 @@
import os import os
import vdf import vdf
from cachier import cachier
import datetime
from src.timing import timeit
cachier = cachier(stale_after=datetime.timedelta(days=1), cache_dir='/tmp/.cache')
@cachier
@timeit
def parse_vdf(steam_vdf_path) -> dict: def parse_vdf(steam_vdf_path) -> dict:
""" """
Reads the Steam vdf file at the given path and returns the corresponding dict. Reads the Steam vdf file at the given path and returns the corresponding dict.
@@ -11,6 +17,7 @@ def parse_vdf(steam_vdf_path) -> dict:
vdf_data = vdf.loads(open(steam_vdf_path, 'r').read()) vdf_data = vdf.loads(open(steam_vdf_path, 'r').read())
return vdf_data return vdf_data
@cachier
def fetch_ids(vdf_json: dict): def fetch_ids(vdf_json: dict):
""" """
Prints all Steam app IDs from the given vdf data. Prints all Steam app IDs from the given vdf data.
@@ -76,11 +83,13 @@ def find_extra_locations(vdf_json):
return steam_library_locations return steam_library_locations
# Reads manifest of individual game vdfs # Reads manifest of individual game vdfs
@cachier
def read_game_vdf(gameID: int, steam_vdf_json: dict, path, game) -> dict: def read_game_vdf(gameID: int, steam_vdf_json: dict, path, game) -> dict:
with open(os.path.join(path, game), 'r') as f: with open(os.path.join(path, game), 'r') as f:
game_vdf = vdf.loads(f.read()) game_vdf = vdf.loads(f.read())
return game_vdf['AppState'] return game_vdf['AppState']
@cachier
def fetchall_vdfs(steam_vdf_json: dict): def fetchall_vdfs(steam_vdf_json: dict):
""" """
Reads all Steam game manifests in the given Steam VDF data and returns a list of dictionaries containing information about each game. Reads all Steam game manifests in the given Steam VDF data and returns a list of dictionaries containing information about each game.
@@ -100,6 +109,7 @@ def fetchall_vdfs(steam_vdf_json: dict):
parsed_game['root_steam_folder'] = path parsed_game['root_steam_folder'] = path
parsed_game['true_path'] = os.path.join(steamapps, "common", parsed_game['installdir']) parsed_game['true_path'] = os.path.join(steamapps, "common", parsed_game['installdir'])
parsed_game['compatdata_path'] = os.path.join(steamapps, "compatdata", str(gameID)) if os.path.exists(os.path.join(steamapps, "compatdata", str(gameID))) else None parsed_game['compatdata_path'] = os.path.join(steamapps, "compatdata", str(gameID)) if os.path.exists(os.path.join(steamapps, "compatdata", str(gameID))) else None
parsed_game['workshop_path'] = os.path.join(steamapps, "workshop", "content", str(gameID)) if os.path.exists(os.path.join(steamapps, "workshop", "content", str(gameID))) else ""
games.append(parsed_game) games.append(parsed_game)
# print("Game name:", parsed_game['name'], "ID:", gameID, "Path:", parsed_game['true_path']) # print("Game name:", parsed_game['name'], "ID:", gameID, "Path:", parsed_game['true_path'])
return games return games
-38
View File
@@ -1,38 +0,0 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='steamPathCLI.sh',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
Generated
+70
View File
@@ -11,6 +11,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/4d/3f/3bc3f1d83f6e4a7fcb834d3720544ca597590425be5ba9db032b2bf322a2/altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff", size = 21212 }, { url = "https://files.pythonhosted.org/packages/4d/3f/3bc3f1d83f6e4a7fcb834d3720544ca597590425be5ba9db032b2bf322a2/altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff", size = 21212 },
] ]
[[package]]
name = "cachier"
version = "3.1.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "portalocker" },
{ name = "watchdog" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d8/95/f17aaba6b786f968a8078c8e86f8004652ba9157d8aeb329837c85d10a43/cachier-3.1.2.tar.gz", hash = "sha256:8ef53b6ae83ba04d8864d2e1f45eb8b46eecb611d0f6a24c006e8fda074c6557", size = 27319 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/9f/11e07e8ffbc921d7c963568937b0290ac9204455a3f3cd866164e82f36ba/cachier-3.1.2-py3-none-any.whl", hash = "sha256:24c0fefd6aef1d38a4337590aba82f3c4bd844df18393ba93c7fd7dcc98da304", size = 24098 },
]
[[package]] [[package]]
name = "macholib" name = "macholib"
version = "1.16.3" version = "1.16.3"
@@ -62,6 +75,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/55/26/d0ad8b448476d0a1e8d3ea5622dc77b916db84c6aa3cb1e1c0965af948fc/pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6", size = 71791 }, { url = "https://files.pythonhosted.org/packages/55/26/d0ad8b448476d0a1e8d3ea5622dc77b916db84c6aa3cb1e1c0965af948fc/pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6", size = 71791 },
] ]
[[package]]
name = "portalocker"
version = "3.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pywin32", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ac/91/8bfe23e1f7f630f2061ef38b5225d9fda9068d6a30fcbc187951e678e630/portalocker-3.1.1.tar.gz", hash = "sha256:ec20f6dda2ad9ce89fa399a5f31f4f1495f515958f0cb7ca6543cef7bb5a749e", size = 43708 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f7/60/1974cfdd5bb770568ddc6f89f3e0df4cfdd1acffd5a609dff5e95f48c6e2/portalocker-3.1.1-py3-none-any.whl", hash = "sha256:80e984e24de292ff258a5bea0e4f3f778fff84c0ae1275dbaebc4658de4aacb3", size = 19661 },
]
[[package]] [[package]]
name = "prompt-toolkit" name = "prompt-toolkit"
version = "3.0.51" version = "3.0.51"
@@ -124,6 +149,22 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d3/e1/ed48c7074145898e5c5b0072e87be975c5bd6a1d0f08c27a1daa7064fca0/pyinstaller_hooks_contrib-2025.4-py3-none-any.whl", hash = "sha256:6c2d73269b4c484eb40051fc1acee0beb113c2cfb3b37437b8394faae6f0d072", size = 434451 }, { url = "https://files.pythonhosted.org/packages/d3/e1/ed48c7074145898e5c5b0072e87be975c5bd6a1d0f08c27a1daa7064fca0/pyinstaller_hooks_contrib-2025.4-py3-none-any.whl", hash = "sha256:6c2d73269b4c484eb40051fc1acee0beb113c2cfb3b37437b8394faae6f0d072", size = 434451 },
] ]
[[package]]
name = "pywin32"
version = "310"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284 },
{ url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748 },
{ url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941 },
{ url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239 },
{ url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839 },
{ url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470 },
{ url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384 },
{ url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039 },
{ url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152 },
]
[[package]] [[package]]
name = "pywin32-ctypes" name = "pywin32-ctypes"
version = "0.2.3" version = "0.2.3"
@@ -160,6 +201,7 @@ name = "steamgamepath"
version = "0.1.0" version = "0.1.0"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "cachier" },
{ name = "prompt-toolkit" }, { name = "prompt-toolkit" },
{ name = "pyinstaller" }, { name = "pyinstaller" },
{ name = "rich" }, { name = "rich" },
@@ -168,6 +210,7 @@ dependencies = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "cachier", specifier = ">=3.1.2" },
{ name = "prompt-toolkit", specifier = ">=3.0.51" }, { name = "prompt-toolkit", specifier = ">=3.0.51" },
{ name = "pyinstaller", specifier = ">=6.14.0" }, { name = "pyinstaller", specifier = ">=6.14.0" },
{ name = "rich", specifier = ">=14.0.0" }, { name = "rich", specifier = ">=14.0.0" },
@@ -183,6 +226,33 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/96/60/6456b687cf55cf60020dcd01f9bc51561c3cc84f05fd8e0feb71ce60f894/vdf-3.4-py2.py3-none-any.whl", hash = "sha256:68c1a125cc49e343d535af2dd25074e9cb0908c6607f073947c4a04bbe234534", size = 10357 }, { url = "https://files.pythonhosted.org/packages/96/60/6456b687cf55cf60020dcd01f9bc51561c3cc84f05fd8e0feb71ce60f894/vdf-3.4-py2.py3-none-any.whl", hash = "sha256:68c1a125cc49e343d535af2dd25074e9cb0908c6607f073947c4a04bbe234534", size = 10357 },
] ]
[[package]]
name = "watchdog"
version = "6.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393 },
{ url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392 },
{ url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019 },
{ url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 },
{ url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 },
{ url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 },
{ url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 },
{ url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 },
{ url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 },
{ url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 },
{ url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 },
{ url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 },
{ url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 },
{ url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 },
{ url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 },
{ url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 },
{ url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 },
{ url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 },
{ url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 },
]
[[package]] [[package]]
name = "wcwidth" name = "wcwidth"
version = "0.2.13" version = "0.2.13"