19 Commits

Author SHA1 Message Date
Tickbase
b9d418805f Update dlc_fetcher.py 2024-11-30 11:40:02 +01:00
Tickbase
c99d747642 Update dlc_fetcher.py
Added back debug prints which got removed by accident
2024-11-30 11:19:49 +01:00
Tickbase
2a94f19719 Update README.md 2024-11-29 22:16:26 +01:00
Tickbase
642b68ce91 Update dlc_fetcher.py 2024-11-29 19:23:14 +01:00
Tickbase
eb9b3a1368 Update README.md 2024-11-29 19:22:38 +01:00
Tickbase
068e52c529 Update bug_report.md 2024-10-20 19:21:24 +02:00
Tickbase
7e19ad1ab9 Update README.md 2024-08-22 04:09:13 +02:00
Tickbase
5b9e3fd350 flatpak support? 2024-08-14 13:02:17 +02:00
Tickbase
dab8787f1d Merge pull request #6 from hideki2k02/rework
Propose changes for dramatically faster scanning and fallback options
2024-08-10 19:00:46 +02:00
Nick H.
723c5873b5 Propose os.scandir() change
As explained on https://github.com/Novattz/creamlinux-installer/pull/5 os.walk() is painfully slow as it will crawl on the directories, causing the program to sometimes take 3 minutes (till timeout) for a single game.

This code will dramatically increase the speed of scanning by using os.scandir() but it will require manually settings library paths (i.e. ~/.steam/steam and ~/.local/share/Steam, not steamapps) since it no longer crawls. 

With that in mind I've also added a "fallback" prompt in case no games are found.
2024-08-05 00:41:18 -03:00
Tickbase
649abe709a Update issue templates 2024-07-21 10:28:37 +02:00
Tickbase
41f8e80df1 Update README.md 2024-07-21 04:53:14 +02:00
Tickbase
5a3fafac49 Update issue templates 2024-07-17 10:42:43 +02:00
Tickbase
a2d081d3b6 seperate log files 2024-07-17 10:39:34 +02:00
Tickbase
a13a56cbc3 v1.0.5 2024-07-17 10:24:35 +02:00
Tickbase
6c2306eac4 Merge pull request #3 from boofiboi/patch-2
Improve readme
2024-07-15 05:03:08 +02:00
David Čudek
41680b8c15 Improve readme 2024-07-14 19:00:22 +02:00
Tickbase
e580645892 Read releases 2024-07-13 23:40:35 +02:00
Tickbase
4648a1ad65 Added function to search for steam binary. 2024-07-13 16:36:04 +02:00
4 changed files with 388 additions and 103 deletions

31
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,31 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: Novattz
---
**Before submitting, have you tried:**
- Using smokeapi with Proton? [ ] Yes [ ] No
- Checking if `LD_PRELOAD` is blocked on your system? [ ] Yes [ ] No
**Describe the bug**
- A clear and concise description of what the bug is.
**Terminal output**
- Copy and paste the entire terminal output when running the script.
**Log File Output**
- If the script logged any errors, attach the log file **`script.log`** to this issue.
**Debug Output**
- Run the script with the **`--debug`** argument and attach the log file **`debug_script.log`** to this issue.
**Steam library path**
- Provide the path where your steam library is.
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[ Feature Request ]"
labels: enhancement
assignees: Novattz
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,35 +1,40 @@
# Steam DLC Fetcher and installer for Linux
- Python script designed for linux to automate fetching of DLC id's for steam games and the installation of creamlinux automatically.
# Features # Steam DLC Fetcher and installer for Linux
- Python script designed for linux to automate fetching of DLC id's for steam games and the installation of creamlinux automatically. [Demo/Tutorial](https://www.youtube.com/watch?v=Y1E15rUsdDw)
### Features
- Automatically fetches and lists DLC's for selected steam game(s) installed on the computer. - Automatically fetches and lists DLC's for selected steam game(s) installed on the computer.
- Automatically installs creamlinux and its components into selected steam games, excluding and handling specific config files. - Automatically installs creamlinux and its components into selected steam games, excluding and handling specific config files.
- Provides a simple cli to navigate and operate the entire process. - Provides a simple cli to navigate and operate the entire process.
# Demo ## Usage
https://www.youtube.com/watch?v=22LDDUoBvus&ab_channel=Nova ### Prerequisites
# To do
- Cross reference dlc files and dlc id's. Incase dlc id's and dlc files differ in terms of quantity it will notify the user.
- Possibly add functionality to search for dlc files/automatically installing them.
- Add the possibility to install cream/smokeapi for games running proton.
- Check if the game already has dlc files installed
- Gui?
# Prerequisites
- `python 3.x` - `python 3.x`
- `requests` library - `requests` library
- `zipfile` library - `zipfile` library
- `tqdm` >=4.65.0
### Installation
# Usage
- Clone the repo or download the script. - Clone the repo or download the script.
- Navigate to the directory containing the script. - Navigate to the directory containing the script.
- Run the script using python. - Run the script using python.
```bash
python dlc_fetcher.py
```
# Issues? #### OR
Use this one-line shell script.
```bash
git clone https://github.com/Novattz/creamlinux-installer;cd creamlinux-installer;python dlc_fetcher.py
```
## TODO
- [ ] Cross reference dlc files and dlc id's. Incase dlc id's and dlc files differ in terms of quantity it will notify the user.
- [ ] Possibly add functionality to search for dlc files/automatically installing them.
- [ ] Add the possibility to install cream/smokeapi for games running proton.
- [ ] Check if the game already has dlc files installed
- [ ] Gui?
- [ ] Add checker for configs already applied to games. (i.e script will check for new dlc id's for already applied games.)
- [ ] Add a way to check if a game blocks LD_PRELOAD.
### Issues?
- Open a issue and attach all relevant errors/logs. - Open a issue and attach all relevant errors/logs.
# Credits # Credits

View File

@@ -4,24 +4,77 @@ import requests
import zipfile import zipfile
import time import time
import stat import stat
import subprocess
from collections import defaultdict
import logging
import argparse
from concurrent.futures import ThreadPoolExecutor
from tqdm import tqdm
import shutil
LOG_FILE = 'script.log' LOG_FILE = 'script.log'
DEBUG_FILE = 'debug_script.log'
TIMEOUT = 180 # Timeout in seconds (3 minutes)
def setup_logging(debug):
log_format = '%(asctime)s [%(levelname)s] %(message)s'
date_format = '%m-%d %H:%M:%S'
if debug:
logging.basicConfig(filename=DEBUG_FILE, level=logging.DEBUG, format=log_format, datefmt=date_format)
else:
logging.basicConfig(filename=LOG_FILE, level=logging.ERROR, format=log_format, datefmt=date_format)
def clear_screen(): def clear_screen():
os.system('cls' if os.name == 'nt' else 'clear') os.system('cls' if os.name == 'nt' else 'clear')
def log_error(message):
logging.error(message)
print(message)
def log_debug(message):
logging.debug(message)
def read_steam_registry():
registry_path = os.path.expanduser('~/.steam/registry.vdf')
if os.path.exists(registry_path):
log_debug(f"Found Steam registry file: {registry_path}")
with open(registry_path, 'r') as f:
content = f.read()
install_path = re.search(r'"InstallPath"\s*"([^"]+)"', content)
if install_path:
return install_path.group(1)
return None
def check_requirements():
required_commands = ['which', 'steam']
required_packages = ['requests', 'tqdm']
for cmd in required_commands:
if not subprocess.run(['which', cmd], capture_output=True).returncode == 0:
print(f"Missing required command: {cmd}")
return False
for package in required_packages:
try:
__import__(package)
except ImportError:
print(f"Missing required package: {package}")
return False
return True
def fetch_latest_version(): def fetch_latest_version():
try: try:
response = requests.get("https://api.github.com/repos/Novattz/creamlinux-installer/releases/latest") response = requests.get("https://api.github.com/repos/Novattz/creamlinux-installer/releases/latest")
data = response.json() data = response.json()
return data['tag_name'] return data['tag_name']
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
log_message(f"Failed to fetch latest version: {str(e)}") log_error(f"Failed to fetch latest version: {str(e)}")
return "Unknown" return "Unknown"
def show_header(app_version): def show_header(app_version, debug_mode):
clear_screen() clear_screen()
cyan = '\033[96m' cyan = '\033[96m'
red = '\033[91m'
reset = '\033[0m' reset = '\033[0m'
print(f"{cyan}") print(f"{cyan}")
print(r""" print(r"""
@@ -39,13 +92,32 @@ def show_header(app_version):
> Version: {app_version} > Version: {app_version}
{reset} {reset}
""") """)
if debug_mode:
print(f"{red} [Running in DEBUG mode]{reset}\n")
print()
app_version = fetch_latest_version() app_version = fetch_latest_version()
#app_version = "TESTING / LETS NOT OVERLOAD GITHUB FOR NO REASON"
def log_message(message): def filter_games(games_list, search_term):
with open(LOG_FILE, 'a') as log_file: filtered = [(idx, item) for idx, item in enumerate(games_list)
log_file.write(f"{message}\n") if search_term.lower() in item[1][0].lower()]
print(message) if not filtered:
print("No games found matching your search.")
return filtered
def select_multiple_games(games_list):
while True:
selections = input("Enter game numbers (comma-separated) or 'all': ").strip()
try:
if selections.lower() == 'all':
return list(range(len(games_list)))
numbers = [int(x.strip()) - 1 for x in selections.split(',')]
if all(0 <= n < len(games_list) for n in numbers):
return numbers
print("Some selections were out of range. Please try again.")
except ValueError:
print("Invalid input. Please enter numbers separated by commas.")
def parse_vdf(file_path): def parse_vdf(file_path):
library_paths = [] library_paths = []
@@ -55,61 +127,126 @@ def parse_vdf(file_path):
paths = re.findall(r'"path"\s*"(.*?)"', content, re.IGNORECASE) paths = re.findall(r'"path"\s*"(.*?)"', content, re.IGNORECASE)
library_paths.extend([os.path.normpath(path) for path in paths]) library_paths.extend([os.path.normpath(path) for path in paths])
except Exception as e: except Exception as e:
log_message(f"Failed to read {file_path}: {str(e)}") log_error(f"Failed to read {file_path}: {str(e)}")
return library_paths return library_paths
def find_steam_library_folders(): def find_steam_binary():
base_paths = [ try:
result = subprocess.run(['which', 'steam'], stdout=subprocess.PIPE)
steam_path = result.stdout.decode('utf-8').strip()
if steam_path:
return os.path.dirname(steam_path)
except Exception as e:
log_error(f"Failed to locate steam binary: {str(e)}")
return None
def find_steam_library_folders(manual_path=""):
search_list = [
# Default
os.path.expanduser('~/.steam/steam'), os.path.expanduser('~/.steam/steam'),
os.path.expanduser('~/.local/share/Steam'), os.path.expanduser('~/.local/share/Steam'),
os.path.expanduser('~/home/deck/.steam/steam'),
os.path.expanduser('~/home/deck/.local/share/Steam'), # Steam Deck
'/mnt', '/media', os.path.expanduser('/home/deck/.steam/steam'),
'/run/media/mmcblk0p1/steamapps' os.path.expanduser('/home/deck/.local/share/Steam'),
# Others
'/mnt/Jogos/Steam',
'/run/media/mmcblk0p1',
# Flatpak
os.path.expanduser('~/.var/app/com.valvesoftware.Steam/.local/share/Steam'),
os.path.expanduser('~/.var/app/com.valvesoftware.Steam/data/Steam/steamapps/common')
] ]
library_folders = [] library_folders = []
try: try:
for base_path in base_paths: if manual_path:
if os.path.exists(base_path): log_debug(f"Manual game path set to \"{manual_path}\" skipping path lookup")
for root, dirs, files in os.walk(base_path, topdown=True): library_folders.append(manual_path)
if 'steamapps' in dirs: else:
steamapps_path = os.path.join(root, 'steamapps') steam_binary_path = find_steam_binary()
if steam_binary_path and steam_binary_path not in search_list:
log_debug(f"Found Steam Binary path! adding it to search paths: {steam_binary_path}")
search_list.append(steam_binary_path)
steam_install_path = read_steam_registry()
if steam_install_path and steam_install_path not in search_list:
log_debug(f"Found Steam Binary path! adding it to search paths: {steam_install_path}")
search_list.append(steam_install_path)
log_debug(f"Paths that will be searched: {search_list}")
for search_path in search_list:
if os.path.exists(search_path):
log_debug(f"Scanning path: {search_path}")
steamapps_path = str(os.path.normpath(f"{search_path}/steamapps"))
if os.path.exists(steamapps_path):
library_folders.append(steamapps_path) library_folders.append(steamapps_path)
log_debug(f"Found steamapps folder: {steamapps_path}")
vdf_path = os.path.join(steamapps_path, 'libraryfolders.vdf') vdf_path = os.path.join(steamapps_path, 'libraryfolders.vdf')
if os.path.exists(vdf_path): if os.path.exists(vdf_path):
log_debug(f"Found libraryfolders.vdf: {vdf_path}")
additional_paths = parse_vdf(vdf_path) additional_paths = parse_vdf(vdf_path)
for path in additional_paths: for path in additional_paths:
new_steamapps_path = os.path.join(path, 'steamapps') new_steamapps_path = os.path.join(path, 'steamapps')
if os.path.exists(new_steamapps_path): if os.path.exists(new_steamapps_path):
library_folders.append(new_steamapps_path) library_folders.append(new_steamapps_path)
dirs[:] = [] # Prevent further scanning into subdirectories log_debug(f"Added additional steamapps folder: {new_steamapps_path}")
if not library_folders:
raise FileNotFoundError("No Steam library folders found.") if not library_folders:
raise FileNotFoundError("No Steam library folders found.")
log_debug(f"Total Steam library folders found: {len(library_folders)}")
except Exception as e: except Exception as e:
log_message(f"Error finding Steam library folders: {e}") log_error(f"Error finding Steam library folders: {e}")
log_error("Scanned paths:")
for path in search_list:
log_error(f" - {path}")
return library_folders return library_folders
def process_acf_file(folder, item):
try:
app_id, game_name, install_dir = parse_acf(os.path.join(folder, item))
if app_id and game_name:
install_path = os.path.join(folder, 'common', install_dir)
if os.path.exists(install_path):
return app_id, game_name, install_path
except Exception as e:
log_error(f"Error processing {item}: {e}")
return None
def find_steam_apps(library_folders): def find_steam_apps(library_folders):
acf_pattern = re.compile(r'^appmanifest_(\d+)\.acf$') acf_pattern = re.compile(r'^appmanifest_(\d+)\.acf$')
games = {} games = {}
try:
with ThreadPoolExecutor() as executor:
futures = []
for folder in library_folders: for folder in library_folders:
if os.path.exists(folder): if os.path.exists(folder):
for item in os.listdir(folder): log_debug(f"Scanning folder for ACF files: {folder}")
if acf_pattern.match(item): folder_items = os.listdir(folder)
try: acf_count = 0
app_id, game_name, install_dir = parse_acf(os.path.join(folder, item)) with tqdm(total=len(folder_items), desc=f"Scanning {os.path.basename(folder)}") as pbar:
if app_id and game_name: for item in folder_items:
install_path = os.path.join(folder, 'common', install_dir) if acf_pattern.match(item):
if os.path.exists(install_path): acf_count += 1
cream_installed = 'Cream installed' if 'cream.sh' in os.listdir(install_path) else '' futures.append(executor.submit(process_acf_file, folder, item))
games[app_id] = (game_name, cream_installed, install_path) pbar.update(1)
except Exception as e: log_debug(f"Found {acf_count} ACF files in {folder}")
log_message(f"Error parsing {item}: {e}")
for future in futures:
result = future.result()
if result:
app_id, game_name, install_path = result
cream_installed = 'Cream installed' if os.path.exists(os.path.join(install_path, 'cream.sh')) else ''
log_debug(f"Found game: {game_name} (App ID: {app_id})")
games[app_id] = (game_name, cream_installed, install_path)
if not games: if not games:
raise FileNotFoundError("No Steam games found.") log_error("No Steam games found.")
except Exception as e: log_debug(f"Total games found: {len(games)}")
log_message(f"Error finding Steam apps: {e}")
return games return games
def parse_acf(file_path): def parse_acf(file_path):
@@ -121,7 +258,7 @@ def parse_acf(file_path):
install_dir = re.search(r'"installdir"\s+"([^"]+)"', data) install_dir = re.search(r'"installdir"\s+"([^"]+)"', data)
return app_id.group(1), name.group(1), install_dir.group(1) return app_id.group(1), name.group(1), install_dir.group(1)
except Exception as e: except Exception as e:
log_message(f"Error reading ACF file {file_path}: {e}") log_error(f"Error reading ACF file {file_path}: {e}")
return None, None, None return None, None, None
def fetch_dlc_details(app_id): def fetch_dlc_details(app_id):
@@ -130,93 +267,185 @@ def fetch_dlc_details(app_id):
response = requests.get(base_url) response = requests.get(base_url)
data = response.json() data = response.json()
if app_id not in data or "data" not in data[app_id]: if app_id not in data or "data" not in data[app_id]:
log_message("Error: Unable to fetch game details.")
return [] return []
game_data = data[app_id]["data"] game_data = data[app_id]["data"]
dlcs = game_data.get("dlc", []) dlcs = game_data.get("dlc", [])
dlc_details = [] dlc_details = []
for dlc_id in dlcs:
try: with tqdm(total=len(dlcs), desc="Fetching DLC details") as pbar:
time.sleep(0.3) for dlc_id in dlcs:
dlc_url = f"https://store.steampowered.com/api/appdetails?appids={dlc_id}" try:
dlc_response = requests.get(dlc_url) time.sleep(0.3)
if dlc_response.status_code == 200: dlc_url = f"https://store.steampowered.com/api/appdetails?appids={dlc_id}"
dlc_data = dlc_response.json() dlc_response = requests.get(dlc_url)
if str(dlc_id) in dlc_data and "data" in dlc_data[str(dlc_id)]:
dlc_name = dlc_data[str(dlc_id)]["data"].get("name", "Unknown DLC") if dlc_response.status_code == 200:
dlc_details.append({"appid": dlc_id, "name": dlc_name}) dlc_data = dlc_response.json()
else: if str(dlc_id) in dlc_data and "data" in dlc_data[str(dlc_id)]:
log_message(f"Data missing for DLC {dlc_id}") dlc_name = dlc_data[str(dlc_id)]["data"].get("name", "Unknown DLC")
elif dlc_response.status_code == 429: dlc_details.append({"appid": dlc_id, "name": dlc_name})
log_message("Rate limited! Please wait before trying again.") elif dlc_response.status_code == 429:
time.sleep(10) time.sleep(10)
else:
log_message(f"Failed to fetch details for DLC {dlc_id}, Status Code: {dlc_response.status_code}") pbar.update(1)
except Exception as e: except Exception as e:
log_message(f"Exception for DLC {dlc_id}: {str(e)}") log_error(f"Exception for DLC {dlc_id}: {str(e)}")
return dlc_details return dlc_details
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
log_message(f"Failed to fetch DLC details for {app_id}: {e}") log_error(f"Failed to fetch DLC details for {app_id}: {e}")
return [] return []
def install_files(app_id, game_install_dir, dlcs, game_name): def install_files(app_id, game_install_dir, dlcs, game_name):
if dlcs:
print("\nFound DLCs:")
for idx, dlc in enumerate(dlcs, 1):
print(f"{idx}. {dlc['name']} (ID: {dlc['appid']})")
if input("\nProceed with installation? (Y/n): ").lower() != 'n':
return
GREEN = '\033[92m'
YELLOW = '\033[93m'
RESET = '\033[0m'
zip_url = "https://github.com/anticitizn/creamlinux/releases/latest/download/creamlinux.zip" zip_url = "https://github.com/anticitizn/creamlinux/releases/latest/download/creamlinux.zip"
zip_path = os.path.join(game_install_dir, 'creamlinux.zip') zip_path = os.path.join(game_install_dir, 'creamlinux.zip')
try: try:
log_debug(f"Downloading creamlinux.zip from {zip_url}")
response = requests.get(zip_url) response = requests.get(zip_url)
if response.status_code == 200: if response.status_code == 200:
log_debug("Successfully downloaded creamlinux.zip")
with open(zip_path, 'wb') as f: with open(zip_path, 'wb') as f:
f.write(response.content) f.write(response.content)
with zipfile.ZipFile(zip_path, 'r') as zip_ref: with zipfile.ZipFile(zip_path, 'r') as zip_ref:
log_debug(f"Extracting files to {game_install_dir}")
zip_ref.extractall(game_install_dir) zip_ref.extractall(game_install_dir)
os.remove(zip_path) os.remove(zip_path)
log_debug("Removed temporary zip file")
cream_sh_path = os.path.join(game_install_dir, 'cream.sh') cream_sh_path = os.path.join(game_install_dir, 'cream.sh')
os.chmod(cream_sh_path, os.stat(cream_sh_path).st_mode | stat.S_IEXEC) os.chmod(cream_sh_path, os.stat(cream_sh_path).st_mode | stat.S_IEXEC)
log_debug("Set executable permissions for cream.sh")
dlc_list = "\n".join([f"{dlc['appid']} = {dlc['name']}" for dlc in dlcs]) dlc_list = "\n".join([f"{dlc['appid']} = {dlc['name']}" for dlc in dlcs])
cream_api_path = os.path.join(game_install_dir, 'cream_api.ini') cream_api_path = os.path.join(game_install_dir, 'cream_api.ini')
log_debug(f"Writing cream_api.ini with {len(dlcs)} DLCs")
with open(cream_api_path, 'w') as f: with open(cream_api_path, 'w') as f:
f.write(f"APPID = {app_id}\n[config]\nissubscribedapp_on_false_use_real = true\n[methods]\ndisable_steamapps_issubscribedapp = false\n[dlc]\n{dlc_list}") f.write(f"APPID = {app_id}\n[config]\nissubscribedapp_on_false_use_real = true\n[methods]\ndisable_steamapps_issubscribedapp = false\n[dlc]\n{dlc_list}")
print(f"Custom cream_api.ini has been written to {game_install_dir}.") print(f"Custom cream_api.ini has been written to {game_install_dir}.")
print(f"Installation complete. Set launch options in Steam: 'sh ./cream.sh %command%' for {game_name}.") print(f"\n{GREEN}Installation complete!{RESET}")
print(f"\n{YELLOW}Set launch options in Steam:{RESET}")
print(f"{GREEN}'sh ./cream.sh %command%'{RESET} for {game_name}")
else: else:
log_message("Failed to download the files needed for installation.") log_error("Failed to download the files needed for installation.")
except Exception as e: except Exception as e:
log_message(f"Failed to install files for {game_name}: {e}") log_error(f"Failed to install files for {game_name}: {e}")
def uninstall_creamlinux(install_path, game_name):
YELLOW = '\033[93m'
GREEN = '\033[92m'
RESET = '\033[0m'
try:
log_debug(f"Starting uninstallation for {game_name}")
files_to_remove = ['cream.sh', 'cream_api.ini', 'cream_api.so', 'lib32Creamlinux.so', 'lib64Creamlinux.so']
for file in files_to_remove:
file_path = os.path.join(install_path, file)
if os.path.exists(file_path):
log_debug(f"Removing {file}")
os.remove(file_path)
print(f"\n{GREEN}Successfully uninstalled CreamLinux from {game_name}{RESET}")
print(f"\n{YELLOW}Make sure to remove{RESET} {GREEN}'sh ./cream.sh %command%'{RESET} {YELLOW}from launch options{RESET}")
log_debug("Uninstallation completed successfully")
except Exception as e:
log_error(f"Failed to uninstall CreamLinux: {e}")
def main(): def main():
show_header(app_version) parser = argparse.ArgumentParser(description="Steam DLC Fetcher")
parser.add_argument("--manual", metavar='steamapps_path', help="Sets the steamapps path for faster operation", required=False)
parser.add_argument("--debug", action="store_true", help="Enable debug logging")
args = parser.parse_args()
setup_logging(args.debug)
show_header(app_version, args.debug)
if not check_requirements():
print("Missing required dependencies. Please install them and try again.")
return
try: try:
library_folders = find_steam_library_folders() library_folders = find_steam_library_folders(args.manual)
if not library_folders:
print("Falling back to Manual Method since no library folder was found")
steamapps_path = input("Steamapps Path: ")
if len(steamapps_path) > 3:
library_folders = [steamapps_path]
else:
print("Invalid path! Closing the program...")
return
# Do initial game scan
games = find_steam_apps(library_folders) games = find_steam_apps(library_folders)
if games: if not games:
print("Select the game for which you want to fetch DLCs:") print("No Steam games found on this computer or connected drives.")
return
while True:
games_list = list(games.items()) games_list = list(games.items())
# Show game list
print("\nSelect the game(s) for which you want to fetch DLCs:")
GREEN = '\033[92m' GREEN = '\033[92m'
RESET = '\033[0m' RESET = '\033[0m'
for idx, (app_id, (name, cream_status, _)) in enumerate(games_list, 1): for idx, (app_id, (name, cream_status, _)) in enumerate(games_list, 1):
if cream_status: status = f" ({GREEN}Cream installed{RESET})" if cream_status else ""
print(f"{idx}. {GREEN}{name} (App ID: {app_id}) - Cream installed{RESET}") print(f"{idx}. {name} (App ID: {app_id}){status}")
try:
choice = int(input("\nEnter the number of the game: ")) - 1
if not (0 <= choice < len(games_list)):
print("Invalid selection.")
continue
except ValueError:
print("Invalid input. Please enter a number.")
continue
selected_app_id, (selected_game_name, cream_status, selected_install_dir) = games_list[choice]
if cream_status:
print(f"\nCreamLinux is installed for {selected_game_name}. What would you like to do?")
print("1. Fetch DLC IDs")
print("2. Uninstall CreamLinux")
action = input("Enter your choice (1-2): ")
if action == "1":
print(f"\nSelected: {selected_game_name} (App ID: {selected_app_id})")
dlcs = fetch_dlc_details(selected_app_id)
if dlcs:
install_files(selected_app_id, selected_install_dir, dlcs, selected_game_name)
else:
print("No DLCs found for the selected game.")
elif action == "2":
uninstall_creamlinux(selected_install_dir, selected_game_name)
else: else:
print(f"{idx}. {name} (App ID: {app_id})") print("Invalid choice.")
choice = int(input("Enter the number of the game: ")) - 1
if choice < 0 or choice >= len(games_list):
raise ValueError("Invalid selection.")
selected_app_id, (selected_game_name, _, selected_install_dir) = games_list[choice]
print(f"You selected: {selected_game_name} (App ID: {selected_app_id})")
dlcs = fetch_dlc_details(selected_app_id)
if dlcs:
print("DLC IDs found:", [dlc['appid'] for dlc in dlcs]) # Only print app IDs for clarity
install_files(selected_app_id, selected_install_dir, dlcs, selected_game_name)
else: else:
print("No DLCs found for the selected game.") print(f"\nSelected: {selected_game_name} (App ID: {selected_app_id})")
else: dlcs = fetch_dlc_details(selected_app_id)
print("No Steam games found on this computer or connected drives.") if dlcs:
install_files(selected_app_id, selected_install_dir, dlcs, selected_game_name)
else:
print("No DLCs found for the selected game.")
if input("\nWould you like to perform another operation? (y/N): ").lower() != 'y':
break
# Only scan again if user wants to continue
games = find_steam_apps(library_folders)
except Exception as e: except Exception as e:
log_message(f"An error occurred: {e}") logging.exception("An error occurred:")
log_error(f"An error occurred: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()