🎈
For those who would like to download workshop mods without owning the game in steam

Download from third-party websites

Skymods

  • Recommended if you would like to play games in older versions, especially for games that cause mod compatibility issue in newer versions, like paradox games.
  • Older verisons can be accessed from revisions.
  • Supported games are listed in catalogue.
  • Search with keywords or steam item id.
  • Not all mods in workshop can be found.
notion image
notion image
notion image

Download using third-party tool

GGNETWORK

  • You can only download mods that have been downloaded by others before.
  • Mods size are limited.
  • Some games are not supported, like wallpaper engine.
notion image
notion image
notion image

Download with shared steam account

Steamcmd

  • Recommended if you want mods of the latest version, but you have to first find shared accounts
  • Related resources:70Games TelegramTelegramSTEAM FREE ACCOUNTS CHAT 🎮
  • Download steamcmd and login with the shared account.

Batch Download

  • List all items to download inside a file, the format follows:
workshop_download_item {gameID} {itemID}
notion image
  • You can get the gameID from workshop main page
notion image
  • And itemID from the mod page
notion image

Python Script Reference

  • place under the steamcmd dir
  • fill in the login_info
  • create input.txt and fill in the

python

import sys import re import os import subprocess import shutil # ------------ start ------------ # --- Configuration --- # just modify config # name: optional; id: game workshop id; login_info: login account password GAME_CANDIDATES = { 0: {"name": "Wallpaper Engine", "id": "431960", "login_info": "login a b"}, 1: {"name": "Stellaris", "id": "281990", "login_info": "login a b"}, 2: {"name": "RimWorld", "id": "294100", "login_info": "login a b"}, 3: {"name": "Hearts of Iron IV", "id": "394360", "login_info": "login a b"}, } # ------------ end ------------ DEFAULT_INPUT_FILENAME = "input.txt" DEFAULT_OUTPUT_FILENAME = "workshop_script.txt" LOG_FILENAME = "steamcmd_output.log" # Path for verification WORKSHOP_BASE_PATH = "steamapps/workshop/content" # Path for cleanup STEAMAPPS_WORKSHOP_DIR = "steamapps/workshop" # --- Core Functions --- def display_initial_instructions(): """Prints the JavaScript snippets for fetching workshop IDs.""" print("--- How to Fetch Workshop IDs ---") print("Run these commands in your browser's developer console on the Steam Workshop page.") print("\nFor a collection:") print("[...document.querySelectorAll('div.collectionItemDetails > a')].map(item => item.href.split('=')[1])") print("\nFor your subscribed items list:") print("[...document.querySelectorAll('div.workshopItemSubscriptionDetails > a')].map(item => item.href.split('=')[1])") print("-" * 40) def display_welcome(): """Prints the main welcome message and lists available games.""" print("\n--- Steam Workshop Interactive Downloader & Verifier ---") print("This script will format IDs, run SteamCMD, and verify the downloads.") print("\nAvailable Games:") for key, game_info in GAME_CANDIDATES.items(): print(f" [{key}] -> {game_info['name']} (ID: {game_info['id']})") print("-" * 40) def parse_universal_input_file(filename): """ Intelligently parses an input file, detecting if it's a steamcmd script or a JSON-like array of IDs. Returns (app_id, item_ids_set) """ try: with open(filename, 'r') as f: content = f.read() except FileNotFoundError: print(f"[ERROR] Input file '{filename}' not found.") return None, None script_pattern = re.compile(r"workshop_download_item\s+(\d+)\s+(\d+)") json_pattern = re.compile(r'"(\d+)"') script_matches = script_pattern.findall(content) if script_matches: print(f"Detected 'steamcmd script' format in '{filename}'.") app_id = script_matches[0][0] if not all(match[0] == app_id for match in script_matches): print("[ERROR] Inconsistent App IDs found in the script file. Aborting.") return None, None item_ids = {match[1] for match in script_matches} return app_id, item_ids json_matches = json_pattern.findall(content) if json_matches: print(f"Detected 'JSON array' format in '{filename}'.") item_ids = set(json_matches) return None, item_ids print(f"[ERROR] Could not find any valid item IDs in '{filename}'.") return None, None def execute_formatting(item_ids, chosen_game_id, output_filename): """Writes the formatted item IDs to the output file.""" print("\n--- Writing Script File ---") formatted_lines = [f"workshop_download_item {chosen_game_id} {item_id}\n" for item_id in sorted(list(item_ids))] with open(output_filename, 'w') as f: f.writelines(formatted_lines) print(f"Successfully wrote {len(item_ids)} items to '{output_filename}'.") # --- NEW FUNCTION --- def perform_cleanup(app_id): """Removes specific workshop directories and the app's acf file before downloading.""" print("\n--- Performing Pre-run Cleanup ---") # Define paths to the directories and file that need to be removed dirs_to_remove = [ os.path.join(STEAMAPPS_WORKSHOP_DIR, 'downloads'), os.path.join(STEAMAPPS_WORKSHOP_DIR, 'content'), os.path.join(STEAMAPPS_WORKSHOP_DIR, 'temp') ] acf_file_to_remove = os.path.join(STEAMAPPS_WORKSHOP_DIR, f'appworkshop_{app_id}.acf') # Remove directories for dir_path in dirs_to_remove: if os.path.isdir(dir_path): try: shutil.rmtree(dir_path) print(f" Successfully removed directory: {dir_path}") except Exception as e: print(f" [ERROR] Failed to remove directory {dir_path}: {e}") else: print(f" Directory not found, skipping: {dir_path}") # Remove the ACF file if os.path.isfile(acf_file_to_remove): try: os.remove(acf_file_to_remove) print(f" Successfully removed file: {acf_file_to_remove}") except Exception as e: print(f" [ERROR] Failed to remove file {acf_file_to_remove}: {e}") else: print(f" File not found, skipping: {acf_file_to_remove}") def run_steamcmd(login_info, script_filename): """Constructs and runs steamcmd, logging all output to a file in real-time.""" steamcmd_exec = "steamcmd.sh" if sys.platform != "win32" else "steamcmd.exe" if not os.path.exists(steamcmd_exec): print(f"\n[ERROR] '{steamcmd_exec}' not found. Please run this script from your steamcmd directory.") return False command = [f"./{steamcmd_exec}"] command.append(f"+{login_info}") command.extend([f"+runscript", script_filename, "+quit"]) print("\n--- Running SteamCMD ---") print(f"Executing command: {' '.join(command)}") print(f"Logging output to '{LOG_FILENAME}' in real-time. This may take a while.") print("Progress: ", end='', flush=True) try: process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1, universal_newlines=True) with open(LOG_FILENAME, 'w') as log_file: for line in iter(process.stdout.readline, ''): log_file.write(line) print(".", end='', flush=True) process.stdout.close() return_code = process.wait() print("\n" + "-" * 40) if return_code == 0: print(f"[SUCCESS] SteamCMD has finished. Log saved to '{LOG_FILENAME}'.") return True else: print(f"[WARNING] SteamCMD finished with exit code {return_code}. Check '{LOG_FILENAME}' for errors.") return True except Exception as e: print(f"\n[ERROR] An error occurred while running SteamCMD: {e}") return False def perform_verification(app_id, expected_ids): """Compares expected IDs with downloaded directories and reports missing ones.""" print("\n--- Verifying Downloads ---") content_path_for_app = os.path.join(WORKSHOP_BASE_PATH, app_id) print(f"Checking for directories in '{content_path_for_app}'...") if not os.path.isdir(content_path_for_app): print(" Warning: Content directory does not exist. All items are considered missing.") existing_dirs = set() else: existing_dirs = {entry for entry in os.listdir(content_path_for_app) if entry.isdigit()} print(f" Expected {len(expected_ids)} items, found {len(existing_dirs)} downloaded directories.") missing_ids = expected_ids.difference(existing_dirs) print("\n--- Verification Complete ---") if not missing_ids: print(f"✅ SUCCESS: All {len(expected_ids)} expected items are present!") else: print(f"❌ MISSING ITEMS: Found {len(missing_ids)} missing item director(y/ies).") print("---------------------------") for item_id in sorted(list(missing_ids)): print(f" - {item_id}") print("---------------------------") print("Suggestion: Copy the missing IDs into a new input file and run this script again.") # --- Main Execution Flow --- def main(): display_initial_instructions() display_welcome() input_filename = input(f"Enter input filename (default: '{DEFAULT_INPUT_FILENAME}'): ") or DEFAULT_INPUT_FILENAME detected_app_id, all_item_ids = parse_universal_input_file(input_filename) if all_item_ids is None: sys.exit(1) chosen_game_info = None if detected_app_id: game_name = "Unknown Game" for game in GAME_CANDIDATES.values(): if game['id'] == detected_app_id: game_name = game['name'] chosen_game_info = game break confirm = input(f"Detected App ID {detected_app_id} ({game_name}). Use this game? (y/n): ").lower() if confirm.strip() != 'y': chosen_game_info = None if not chosen_game_info: chosen_indicator = -1 while chosen_indicator not in GAME_CANDIDATES: try: user_input = input("\nEnter the number for the game you want to use: ") chosen_indicator = int(user_input) chosen_game_info = GAME_CANDIDATES[chosen_indicator] except (ValueError, KeyError): print("[ERROR] Invalid selection. Please enter a valid number.") output_filename = input(f"Enter output script name (default: '{DEFAULT_OUTPUT_FILENAME}'): ") or DEFAULT_OUTPUT_FILENAME execute_formatting(all_item_ids, chosen_game_info['id'], output_filename) # --- MODIFICATION: Added cleanup step before running steamcmd --- perform_cleanup(chosen_game_info['id']) if run_steamcmd(chosen_game_info['login_info'], output_filename): perform_verification(chosen_game_info['id'], all_item_ids) if __name__ == "__main__": main()
Python
 
 
 
 
 
 
 
 
 
 
 
  • After login, type runscript {your_file_name} to download all mods, the mods downloaded will locate in steamapps/content/{gameID} dir
 
Download Youtube 4K Video (1)Chrome extension recommendation (1)
Loading...
CamelliaV
CamelliaV
Java;前端;AI;ACGN;
公告
计划:
  • LLM相关
  • 支付业务 & 双token无感刷新
  • (线程池计算优惠方案)天机学堂Day09-Day12复盘-优惠劵业务
  • (业务复盘,技术汇总)天机学堂完结复盘
  • hot 100
 
2024-2026CamelliaV.

CamelliaV | Java;前端;AI;ACGN;


  1. 1 BRIGHTEST HEART 高柳知葉
  2. 2 Raven Oliver Good
  3. 3 Against the Tide(逆潮) 鸣潮先约电台/Forts
  4. 4 给予你的爱 Xi YuaN/Digital Vengeance/唢清
  5. 5 スペルビア帝国/夜 平松建治
  6. 6 Imagination QQHHh
  7. 7 virtues QQHHh
  8. 8 Tricolor (short ver.) Digital Vengeance/44
  9. 9 港口夜 - 四周年 月代彩
  10. 10 神よ、その黄昏よ 金﨑猛
  11. 11 絆炎 (English Ver) Katherine Eames
  12. 12 ラストエンゲージ~祈りの呪文 馬場泰久
  13. 13 an evening calm fripSide
  14. 14 フレスベルグの少女~風花雪月~ Caro
  15. 15 Answer 北原春希/小木曽雪菜
  16. 16 Kiss Kiss Kiss BENI
  17. 17 远航高歌 染音若蔡/阿南
  18. 18 Sentimental Blue Trident
  19. 19 目指す先にあるもの Falcom Sound Team J.D.K.
  20. 20 Night City r e l/Artemis Delta
  21. 21 Gimme×Gimme P*Light/Giga/初音ミク/鏡音リン
  22. 22 桃幻浪漫 Airots/Active Planets & AUGUST
  23. 23 DESIRE 美郷あき
  24. 24 镜花堂(feat.芬璃尔) 幻塔手游/Rux
  25. 25 she was sitting under the osmanthus tree 梶浦由記
BRIGHTEST HEART - 高柳知葉
00:00 / 00:00