Compare commits
12 Commits
1.0.0
..
ba18af4a70
| Author | SHA1 | Date | |
|---|---|---|---|
| ba18af4a70 | |||
| d977b2b621 | |||
| 26840e7a40 | |||
| 153bf640be | |||
| 711579e2b1 | |||
| a4f0e5eece | |||
| d8a49d04a3 | |||
| 9c2073f1ad | |||
| 4c39ab90dc | |||
| 10e4b73b00 | |||
| e3c35285f2 | |||
| 02731ad9ca |
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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}}"
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
+23
-10
@@ -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.
|
||||||
@@ -92,14 +101,18 @@ def fetchall_vdfs(steam_vdf_json: dict):
|
|||||||
for library in steam_vdf_json["libraryfolders"]:
|
for library in steam_vdf_json["libraryfolders"]:
|
||||||
path = steam_vdf_json['libraryfolders'][library]['path']
|
path = steam_vdf_json['libraryfolders'][library]['path']
|
||||||
steamapps = os.path.join(path, "steamapps")
|
steamapps = os.path.join(path, "steamapps")
|
||||||
for game in os.listdir(steamapps):
|
try:
|
||||||
if game.endswith(".acf"):
|
for game in os.listdir(steamapps):
|
||||||
gameID = int(game.split('.')[0].split('_')[1])
|
if game.endswith(".acf"):
|
||||||
parsed_game = read_game_vdf(gameID, steam_vdf_json, steamapps, game)
|
gameID = int(game.split('.')[0].split('_')[1])
|
||||||
parsed_game['acf_path'] = os.path.join(steamapps, game)
|
parsed_game = read_game_vdf(gameID, steam_vdf_json, steamapps, game)
|
||||||
parsed_game['root_steam_folder'] = path
|
parsed_game['acf_path'] = os.path.join(steamapps, game)
|
||||||
parsed_game['true_path'] = os.path.join(steamapps, "common", parsed_game['installdir'])
|
parsed_game['root_steam_folder'] = path
|
||||||
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['true_path'] = os.path.join(steamapps, "common", parsed_game['installdir'])
|
||||||
games.append(parsed_game)
|
parsed_game['compatdata_path'] = os.path.join(steamapps, "compatdata", str(gameID)) if os.path.exists(os.path.join(steamapps, "compatdata", str(gameID))) else None
|
||||||
# print("Game name:", parsed_game['name'], "ID:", gameID, "Path:", parsed_game['true_path'])
|
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)
|
||||||
|
# print("Game name:", parsed_game['name'], "ID:", gameID, "Path:", parsed_game['true_path'])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error processing folder {steamapps}: {e}")
|
||||||
return games
|
return games
|
||||||
|
|||||||
@@ -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,
|
|
||||||
)
|
|
||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user